1.信号量:
{
private int n1, n2, n3;
EventWaitHandle myEventWaitHandle = new EventWaitHandle(false, EventResetMode.ManualReset); //EventResetMode中有手动和自动设置信号量;
//false没默认没有信号,true表示默认有信号。对应的类AutoResetEvent和ManualResetEvent
static void Main(string[] args)
{
Program p = new Program();
Thread t0 = new Thread(new ThreadStart(p.WriteThread));
Thread t1 = new Thread(new ThreadStart(p.ReadThread));
t1.Start();
t0.Start();
Thread t3 = new Thread(new ThreadStart(p.AA));
t3.Start();
Console.ReadLine();
}
private void WriteThread()
{
//允许其他需要等待的线程阻塞
myEventWaitHandle.Reset(); //获得信号并让其他的wait处理等待状态
Console.WriteLine("t1");
n1 = 1;
n2 = 2;
n3 = 3;
myEventWaitHandle.Set(); //允许其他等待的线程继续
}
private void ReadThread()
{
myEventWaitHandle.WaitOne(); //阻塞当前线程,直到收到信号
Console.WriteLine("{0}+{1}+{2}={3}", n1, n2, n3, n1 + n2 + n3);
}
private void AA()
{
myEventWaitHandle.WaitOne(); //阻塞当前线程,直到收到信号
string aa = "";
}
//AutoResetEvent和ManualResetEvent的区别是在waitone后,自动会变成无信号状态,而手动不会,如下面的实例如果设置成手动,则都可以执行,如果设置成
自动, ReadThread和AA方法有一个方法执行不到,因为waitone在自动获得信号后变成了信号状态。
}
2.lock关键字
lock是C#关键词,它将语句块标记为临界区,确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。方法是获取给定对象的互斥锁,执行语句,然后释放该锁。
MSDN上给出了使用lock时的注意事项通常,应避免锁定 public 类型,否则实例将超出代码的控制范围
3.Monitor类
lock就是对Monitor的Enter和Exit的一个封装,而且使用起来更简洁,因此Monitor类的Enter()和Exit()方法的组合使用可以用lock关键字替代 。
另外Monitor类还有几个常用的方法:
TryEnter()能够有效的解决长期死等的问题,如果在一个并发经常发生,而且持续时间长的环境中使用TryEnter,可以有效防止死锁或者长时间 的等待。比如我们可以设置一个等待时间bool gotLock = Monitor.TryEnter(myobject,1000),让当前线程在等待1000秒后根据返回的bool值来决定是否继续下面的操作。
Wait()释放对象上的锁以便允许其他线程锁定和访问该对象。在其他线程访问对象时,调用线程将等待。脉冲信号用于通知等待线程有关对象状态的更改。
Pulse(),PulseAll()向一个或多个等待线程发送信号。该信号通知等待线程锁定对象的状态已更改,并且锁的所有者准备释放该锁。等待线程被 放置在对象的就绪队列中以便它可以最后接收对象锁。一旦线程拥有了锁,它就可以检查对象的新状态以查看是否达到所需状态。
注意:Pulse、PulseAll和Wait方法必须从同步的代码块内调用。
class Program
{
private static object objA = new object();
private static object objB = new object();
static void Main(string[] args)
{
Thread threadA = new Thread(LockA);
Thread threadB = new Thread(LockB);
threadA.Start();
threadB.Start();
Thread.Sleep(4000);
Console.WriteLine("线程结束");
Console.ReadLine();
}
public static void LockA()
{
if (Monitor.TryEnter(objA, 1000))
{
Thread.Sleep(1000);
if (Monitor.TryEnter(objB, 2000))
{
Monitor.Exit(objB);
}
else
{
Console.WriteLine("LockB timeout");
}
Monitor.Exit(objA);
}
Console.WriteLine("LockA");
}
public static void LockB()
{
if (Monitor.TryEnter(objB, 2000))
{
Thread.Sleep(2000);
if (Monitor.TryEnter(objA, 1000))
{
Monitor.Exit(objA);
}
else
{
Console.WriteLine("LockA timeout");
}
Monitor.Exit(objB);
}
Console.WriteLine("LockB");
}
}
本来未产生死锁的,但什么有个超时时间,所以不会发生死锁
4Mutex
EventWaitHandle的名字与Mutex差了很多,不过它可是Mutex不折不扣的兄弟——它和Mutex都是WaitHandle的子类,用法也差不多