线程同步这一方面,因为相对来说用得比较少,每次做多线程相关的问题是都必须重新温习,今天在看异步TCP时,又重新梳理了下。
多线程同步大概有两类:一类是信号量,另一类是互斥,排他
1.信号量:
实例代码如:
- class Program
- {
- 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是关键词,它将语句块标记为临界区,确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。方法是获取给定对象的互斥锁,执行语句,然后释放该锁。
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的子类,用法也差不多
阅读(486) | 评论(0) | 转发(0) |