在C#中,用于同步的主要是Mutex类与Semaphore类。位于System.Threading命名空间中。
在这两个种对象的方法中,P操作对应的是WaitOne()方法,V操作对应的是ReleaseMutex()与Release()方法。
下面是用C#解决几大PV操作经典问题及其变形的代码。
一、生产者消费者问题
1.最简单的情况:一个生产者,一个消费者,共用一个缓冲区进行生产消费。
源代码:
using System;
using System.Threading;
namespace OS
{
class Program
{
static Mutex mutex = new Mutex();
static void Main(string[] args)
{
// int[] buffer;
new Thread(new ThreadStart(Producer)).Start();
new Thread(new ThreadStart(Customer)).Start();
Console.Read();
}
private static void Producer()
{
while (true)
{
mutex.WaitOne();
Console.WriteLine("Producer is working!");
mutex.ReleaseMutex();
Thread.Sleep(400);
}
}
private static void Customer()
{
while (true)
{
mutex.WaitOne();
Console.WriteLine("customer is working");
mutex.ReleaseMutex();
Thread.Sleep(400);
}
}
}
}
2.现在稍微复杂一些,生产者与消费者共用一个大小为n的环形缓冲区。本例中n取10.
源代码:
using System;
using System.Threading;
namespace OS
{
class Program
{
static Mutex mutex = new Mutex();
static Semaphore empty = new Semaphore(10,10);
static Semaphore full = new Semaphore(0,10);
static int[] buffer = new int[10];
static Random rand = new Random();
static void Main(string[] args)
{
new Thread(new ThreadStart(Producer)).Start();
new Thread(new ThreadStart(Customer)).Start();
Console.Read();
}
private static void Producer()
{
uint ppointer=0;
int temp;
while (true)
{
//!!!!Attention!!!!!NEVER MIX Orders
//如果empty与mutex的顺序反了,就会发生死锁!
empty.WaitOne();
mutex.WaitOne();
temp = rand.Next(1, 100);
buffer[ppointer] = temp;
Console.WriteLine("Producer works at {0} with {1}",ppointer,temp);
ppointer = (ppointer + 1)%10;
mutex.ReleaseMutex();
full.Release();
Thread.Sleep(400);
}
}
private static void Customer()
{
uint cpointer=0;
int temp;
while (true)
{
full.WaitOne();
mutex.WaitOne();
temp = rand.Next(1, 100);
temp = buffer[cpointer];
Console.WriteLine("Customer gains at {0} with {1}", cpointer, temp);
cpointer = (cpointer + 1) % 10;
mutex.ReleaseMutex();
empty.Release();
Thread.Sleep(400);
}
}
}
}
3.问题变形:桌上有一个空盘子,只允许放一个水果。爸爸可以放苹果。也可以放橘子。儿子要吃苹果,女儿要吃橘子。试实现之。
using System;
using System.Threading;
namespace OS
{
internal class Program
{
private static Mutex mutex = new Mutex();
private static Semaphore Sempty = new Semaphore(1, 1);
private static Semaphore Sorange = new Semaphore(0, 1);
private static Semaphore Sapple = new Semaphore(0, 1);
private static Fruit buffer = 0;
private static Random rand = new Random();
public enum Fruit
{
Empty,
Apple,
Orange
};
private static void Main(string[] args)
{
new Thread(new ThreadStart(Papa)).Start();
new Thread(new ThreadStart(Son)).Start();
new Thread(new ThreadStart(Daughter)).Start();
Console.Read();
}
private static void Papa()
{
while (true)
{
int temp = 0;
Sempty.WaitOne();
mutex.WaitOne();
temp = rand.Next(1,3);
if (temp == 1)
{
Console.WriteLine("Papa put an apple");
buffer = Fruit.Apple;
mutex.ReleaseMutex();
Sapple.Release();
}
else
{
Console.WriteLine("Papa put an Orange");
buffer = Fruit.Orange;
mutex.ReleaseMutex();
Sorange.Release();
}
Thread.Sleep(400);
}
}
private static void Son()
{
while (true)
{
Sapple.WaitOne();
mutex.WaitOne();
Console.WriteLine("Son eat an {0}", buffer);
mutex.ReleaseMutex();
Sempty.Release();
Thread.Sleep(400);
}
}
private static void Daughter()
{
while (true)
{
Sorange.WaitOne();
mutex.WaitOne();
Console.WriteLine("Daughter eat an {0}", buffer);
mutex.ReleaseMutex();
Sempty.Release();
Thread.Sleep(400);
}
}
}
}
二、哲学家用餐问题
五个哲学家围着桌子共同进餐,每个哲学家两侧各有一支筷子。试设计同步算法,使哲学家都能吃上饭。
using System;
using System.Threading;
namespace PhilosophersProblem
{
class Program
{
static Semaphore[] chopsticks = { new Semaphore(1, 1)
, new Semaphore(1, 1)
, new Semaphore(1, 1)
, new Semaphore(1, 1),
new Semaphore(1, 1), };
static void Main(string[] args)
{
for (int i = 0; i < 5; i++)
{
new Thread(new ParameterizedThreadStart(philosopher)).Start(i);
}
Console.Read();
}
private static void philosopher(object input)
{
int i = (int)input;
chopsticks[i].WaitOne();
chopsticks[(i + 1)%5].WaitOne();
Console.WriteLine("Philosopher{0}: I am eating",i);
Thread.Sleep(1000);
chopsticks[i].Release();
chopsticks[(i + 1)%5].Release();
}
}
}
三、读者写者问题
一个文件,允许多个读者同时读取,只能允许一个写者同时写,写者写的时候不能读。试实现之。
using System;
using System.Threading;
namespace ReaderWriter
{
class ReaderWriter
{
//Warning : Some Error will occur if more than one Reader is newed
//Using Semaphore can solve this however here I take mutex as example to show the concept.
static int Readcount =0 ;
static Mutex WMutex = new Mutex();
static Mutex RMutex = new Mutex();
static int buffer = 0;
static Random rand = new Random();
static void Main(string[] args)
{
new Thread(new ThreadStart(Writer)).Start();
new Thread(new ThreadStart(Reader)).Start();
new Thread(new ThreadStart(Reader)).Start();
Console.Read();
}
private static void Reader()
{
while (true)
{
RMutex.WaitOne();
if (Readcount == 0)
{
WMutex.WaitOne();
}
Readcount++;
RMutex.ReleaseMutex();
Console.WriteLine("I have read this:{0}", buffer.ToString());
RMutex.WaitOne();
Readcount--;
if (Readcount == 0)
{
WMutex.ReleaseMutex();
}
RMutex.ReleaseMutex();
Thread.Sleep(300);
}
}
private static void Writer()
{
while (true)
{
WMutex.WaitOne();
buffer = rand.Next(1, 10);
Console.WriteLine("Write {0}",buffer);
WMutex.ReleaseMutex();
Thread.Sleep(1000);
}
}
}
}
就是这样...