在C#中,用于同步的主要是Mutex类与Semaphore类。位于System.Threading命名空间中。
在这两个种对象的方法中,P操作对应的是WaitOne()方法,V操作对应的是ReleaseMutex()与Release()方法。
下面是用C#解决几大PV操作经典问题及其变形的代码。
一、生产者消费者问题
1.最简单的情况:一个生产者,一个消费者,共用一个缓冲区进行生产消费。
1 using System; 2 using System.Threading; 3 4 namespace PRoducerCustomer1_SingleBuffer 5 { 6 class ProducerCustomer1_SingleBuffer 7 { 8 static Mutex mutex = new Mutex(); 9 static void Main(string[] args)10 {11 new Thread(new ThreadStart(Producer)).Start();12 new Thread(new ThreadStart(Customer)).Start(); 13 Console.Read();14 }15 16 private static void Producer()17 {18 while (true)19 {20 mutex.WaitOne();21 Console.WriteLine("Producer is working!");22 mutex.ReleaseMutex();23 Thread.Sleep(400);24 }25 }26 27 private static void Customer()28 {29 while (true)30 {31 mutex.WaitOne();32 Console.WriteLine("customer is working");33 mutex.ReleaseMutex();34 Thread.Sleep(400);35 }36 }37 }38 }
2.现在稍微复杂一些,生产者与消费者共用一个大小为n的环形缓冲区。本例中n取10.
1 using System; 2 using System.Threading; 3 4 namespace ProducerCustomer2_MultiBuffer 5 { 6 class ProducerCustomer2_MultiBuffer 7 { 8 static Mutex mutex = new Mutex(); 9 static Semaphore empty = new Semaphore(10,10);10 static Semaphore full = new Semaphore(0,10);11 static int[] buffer = new int[10];12 static Random rand = new Random();13 14 static void Main(string[] args)15 {16 new Thread(new ThreadStart(Producer)).Start();17 new Thread(new ThreadStart(Customer)).Start();18 Console.Read();19 }20 21 private static void Producer()22 {23 uint ppointer=0;24 int temp;25 while (true)26 { 27 //!!!!Attention!!!!!NEVER MIX Orders28 //如果empty与mutex的顺序反了,就会发生死锁!29 empty.WaitOne();30 mutex.WaitOne();31 temp = rand.Next(1, 100);32 buffer[ppointer] = temp;33 Console.WriteLine("Producer works at {0} with {1}",ppointer,temp);34 ppointer = (ppointer + 1)%10;35 mutex.ReleaseMutex();36 full.Release();37 Thread.Sleep(400);38 }39 }40 41 private static void Customer()42 {43 uint cpointer=0;44 int temp;45 while (true)46 {47 full.WaitOne();48 mutex.WaitOne();49 temp = rand.Next(1, 100);50 temp = buffer[cpointer];51 Console.WriteLine("Customer gains at {0} with {1}", cpointer, temp);52 cpointer = (cpointer + 1) % 10;53 mutex.ReleaseMutex();54 empty.Release();55 Thread.Sleep(400);56 }57 }58 }59 }
3.问题再升级:
桌上有一个空盘子,只允许放一个水果。爸爸可以放苹果。也可以放橘子。儿子要吃苹果,女儿要吃橘子。试实现之。
1 using System; 2 using System.Threading; 3 4 namespace ProducerCustomer3_Fruit 5 { 6 internal class ProducerCustomer3_Fruit 7 { 8 private static Mutex mutex = new Mutex(); 9 private static Semaphore Sempty = new Semaphore(1, 1);10 private static Semaphore Sorange = new Semaphore(0, 1);11 private static Semaphore Sapple = new Semaphore(0, 1);12 13 private static Fruit buffer = 0;14 private static Random rand = new Random();15 16 public enum Fruit17 {18 Empty,19 Apple,20 Orange21 };22 23 private static void Main(string[] args)24 {25 new Thread(new ThreadStart(Papa)).Start();26 new Thread(new ThreadStart(Son)).Start();27 new Thread(new ThreadStart(Daughter)).Start();28 Console.Read();29 }30 31 private static void Papa()32 {33 while (true)34 {35 int temp = 0;36 Sempty.WaitOne();37 mutex.WaitOne();38 temp = rand.Next(1,3);39 if (temp == 1)40 {41 Console.WriteLine("Papa put an apple");42 buffer = Fruit.Apple;43 mutex.ReleaseMutex();44 Sapple.Release();45 }46 else47 {48 Console.WriteLine("Papa put an Orange");49 buffer = Fruit.Orange;50 mutex.ReleaseMutex();51 Sorange.Release();52 }53 Thread.Sleep(400);54 }55 }56 57 private static void Son()58 {59 while (true)60 {61 Sapple.WaitOne();62 mutex.WaitOne();63 Console.WriteLine("Son eat an {0}", buffer);64 mutex.ReleaseMutex();65 Sempty.Release();66 Thread.Sleep(400);67 }68 }69 70 private static void Daughter()71 {72 while (true)73 {74 Sorange.WaitOne();75 mutex.WaitOne();76 Console.WriteLine("Daughter eat an {0}", buffer);77 mutex.ReleaseMutex();78 Sempty.Release();79 Thread.Sleep(400);80 }81 }82 }83 }
二、哲学家进餐问题
五个哲学家围着桌子共同进餐,每个哲学家两侧各有一支筷子。试设计同步算法,使哲学家都能吃上饭。
1 using System; 2 using System.Threading; 3 4 namespace PhilosophersProblem 5 { 6 class PhilosophersProblem 7 { 8 static Semaphore[] chopsticks = { new Semaphore(1, 1) 9 , new Semaphore(1, 1)10 , new Semaphore(1, 1)11 , new Semaphore(1, 1),12 new Semaphore(1, 1), };13 14 static void Main(string[] args)15 {16 for (int i = 0; i < 5; i++)17 {18 new Thread(new ParameterizedThreadStart(philosopher)).Start(i);19 }20 Console.Read();21 }22 23 private static void philosopher(object input)24 {25 int i = (int)input;26 chopsticks[i].WaitOne();27 chopsticks[(i + 1)%5].WaitOne();28 29 Console.WriteLine("Philosopher{0}: I am eating",i);30 Thread.Sleep(1000);31 32 chopsticks[i].Release();33 chopsticks[(i + 1)%5].Release();34 }35 }36 }
对于此类问题,应尽量使用信号量集或者and型信号量以避免死锁。
三、读者写者问题
新闻热点
疑难解答