c#中的多线程同步
lock和Monitor依靠一种“令牌”对象来实现进程的同步,下面看一段示范代码:
class Example
{
int count = 0;
object o = new object();//令牌对象
static void Main(string[] args)
{
Example e=new Example();
Thread pthread = new Thread(e.produce);
Thread cthread = new Thread(e.consume);
pthread.Start();
cthread.Start();
}
public void produce()
{
while (true)
{
lock (o)
{
count = count + 1;
}
}
}
public void consume()
{
while (true)
{
lock (o)
{
count = count - 1;
}
}
}
}
在程序中,我们需要产生两个生产和消费的线程,但是两个线程对count的访问必须是互斥的,也就是要实现两个现场的同步。在上面的代码中,首先实例化一个令牌对象o,当需要操作互斥变量count的时候,我就用lock关键字去取令牌,如果此时令牌可以拿到,就执行对count的操作,然后释放令牌。如果此时令牌在另外一个线程手里,就等待知道该令牌被释放。Monitor的使用与lock很相似,下面附上使用代码,不再另加说明:
Monitor.Enter(o);
count=count+1;
Monitor.Exit(o);
Mutex是使用互斥的机制来实现进程的同步,Mutex不需要使用额外的令牌对象。下面是用Mutex来解决著名的生产者消费者问题,设定消费者和生产者各3个,公共区容量为5,生产100个,下面看代码:
class Program
{
static void Main(string[] args)
{
ProduceAndConsume pac=new ProduceAndConsume();
Thread pthread1 = new Thread(pac.produce);
Thread pthread2 = new Thread(pac.produce);
Thread pthread3 = new Thread(pac.produce);
Thread cthread1 = new Thread(pac.consume);
Thread cthread2 = new Thread(pac.consume);
Thread cthread3 = new Thread(pac.consume);
pthread1.Start();
pthread2.Start();
pthread3.Start();
cthread1.Start();
cthread2.Start();
cthread3.Start();
}
}
class ProduceAndConsume
{
private int count = 0;
private int pID=0;
private int cID = 0;
private object mutexobjext = new object();
private Mutex IDmux = new Mutex();//该互斥量是对产品序号的互斥
private Mutex Countmux = new Mutex();//该互斥量是对公共区产品数量的互斥
public void produce()
{
while (true)
{
IDmux.WaitOne();//申请产品序号互斥,不行则等待
if (pID >= 100)
{
//达到一百个,释放互斥,线程结束
IDmux.ReleaseMutex();
break;
}
Countmux.WaitOne();//申请公共区数量互斥
if (count >= 5)
{
//公共区满,生产线程释放互斥后睡眠
Countmux.ReleaseMutex();
IDmux.ReleaseMutex();
Thread.Sleep(2);
continue;
}
else
{
//公共区数量加一,并打印生产产品的序号信息,完成后释放互斥
count = count + 1;
Countmux.ReleaseMutex();
pID = pID + 1;
Console.WriteLine("Has produced {0}..", pID);
IDmux.ReleaseMutex();
Thread.Sleep(1);
}
}
}
public void consume()
{
//类似于produce(),不同是消费过程
while (true)
{
IDmux.WaitOne();
if(cID>=100)
{
IDmux.ReleaseMutex();
break;
}
Countmux.WaitOne();
if (count <= 0)
{
Countmux.ReleaseMutex();
IDmux.ReleaseMutex();
Thread.Sleep(2);
continue;
}
else
{
count = count - 1;
Countmux.ReleaseMutex();
cID = cID + 1;
Console.WriteLine("Has Consume {0}", cID);
IDmux.ReleaseMutex();
Thread.Sleep(1);
}
}
}
}
下面是执行结果,可以看到进程已经很好的同步了 :
Has produced 1..
Has produced 2..
Has produced 3..
Has produced 4..
Has produced 5..
Has Consume 1
Has produced 6..
Has Consume 2
Has Consume 3
Has Consume 4
Has produced 7..
Has Consume 5
Has Consume 6
Has produced 8..
Has produced 9..
Has Consume 7
Has produced 10..
Has Consume 8
Has Consume 9
Has Consume 10
Has produced 11..
Has produced 12..
Has Consume 11
Has produced 13..
Has produced 14..
Has produced 15..
Has Consume 12
Has produced 16..
Has Consume 13
Has Consume 14
Has produced 17..
Has produced 18..
Has Consume 15
Has produced 19..
Has Consume 16
Has produced 20..
Has Consume 17
Has produced 21..
Has produced 22..
Has Consume 18
Has Consume 19
Has Consume 20
Has produced 23..
Has Consume 21
Has Consume 22
Has produced 24..
Has Consume 23
Has produced 25..
Has produced 26..
Has Consume 24
Has produced 27..
Has Consume 25
Has Consume 26
Has produced 28..
Has Consume 27
Has Consume 28
Has produced 29..
Has produced 30..
Has Consume 29
Has produced 31..
Has Consume 30
Has Consume 31
Has produced 32..
Has Consume 32
Has produced 33..
Has produced 34..
Has produced 35..
..................................