C# 线程同步(使用ManuaIResetEventSlim类)
本节将描述如何使用ManualResetEventSlim类来在线程间以更灵活的方式传递信号。运行结果。
使用ManuaIResetEventSlim类
本节将描述如何使用ManualResetEventSlim类来在线程间以更灵活的方式传递信号。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace 使用ManuaIResetEventSlim类
{
internal class Program
{
static ManualResetEventSlim _mainEvent=new ManualResetEventSlim(false);
static void Main(string[] args)
{
var t1 = new Thread(() => TravelThroughGates("Thread 1", 5));
var t2 = new Thread(() => TravelThroughGates("Thread 2", 6));
var t3 = new Thread(() => TravelThroughGates("Thread 3", 12));
t1.Start();
t2.Start();
t3.Start();
Thread.Sleep(TimeSpan.FromSeconds(6));
Console.WriteLine("The gates are now open!");
_mainEvent.Set();
Thread.Sleep(TimeSpan.FromSeconds(2));
_mainEvent.Set();
Console.WriteLine("The gates have been closed!");
Thread.Sleep(TimeSpan.FromSeconds(10));
Console.WriteLine("The gates are now open for the second time!");
_mainEvent.Set();
Thread.Sleep(TimeSpan.FromSeconds(2));
Console.WriteLine("The gates have been closed!");
_mainEvent.Set();
}
static void TravelThroughGates(string threadName,int seconds)
{
Console.WriteLine("{0} falls to sleep", threadName);
Thread.Sleep(TimeSpan.FromSeconds(seconds));
Console.WriteLine("{0} waits for the gates to open!", threadName);
_mainEvent.Wait();
Console.WriteLine("{0} enters the gates!", threadName);
}
}
}
运行结果
Thread 1 falls to sleep
Thread 2 falls to sleep
Thread 3 falls to sleep
Thread 1 waits for the gates to open!
The gates are now open!
Thread 1 enters the gates!
Thread 2 waits for the gates to open!
Thread 2 enters the gates!
The gates have been closed!
Thread 3 waits for the gates to open!
Thread 3 enters the gates!
The gates are now open for the second time!
The gates have been closed!
工作原理
当主程序启动时,首先创建了ManualResetEventSlim类的一个实例。然后启动了三个线
程,等待事件信号通知它们继续执行。
ManualResetEvnetSlim的整个工作方式有点像人群通过大门。2.5节中讨论过的
AutoResetEvent事件像一个旋转门,一次只允许一人通过。ManualResetEventSIim是Manual-
ResetEvent的混合版本,一直保持大门敞开直到手动调用Reset方法。当调用mainEvent.Set时,相当于打开了大门从而允许准备好的线程接收信号并继续工作。然而线程3还处于睡眠
状态,没有赶上时间。当调用mamEvent.Reset相当于关闭了大门。最后一个线程已经准备
好执行,但是不得不等待下一个信号,即要等待好几秒钟。
使用CountDownEvent类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace 使用CountDownEvent类
{
internal class Program
{
static CountdownEvent _countdown = new CountdownEvent(2);
static void Main(string[] args)
{
Console.WriteLine("Starting two operations");
var t1 = new Thread(() => PerformOperation("operation 1 is completed", 4));
var t2 = new Thread(() => PerformOperation("operation 2 is completed", 8));
t1.Start();
t2.Start();
_countdown.Wait();
Console.WriteLine("Both operation have been completed.");
_countdown.Dispose();
}
static void PerformOperation(string message,int secondes)
{
Thread.Sleep(TimeSpan.FromSeconds(secondes));
Console.WriteLine(message);
_countdown.Signal();
}
}
}
运行结果
Starting two operations
operation 1 is completed
operation 2 is completed
Both operation have been completed.
工作原理
当主程序启动时,创建了一个CountdownEvent实例,在其构造函数中指定了当两个操
作完成时会发出信号。然后我们启动了两个线程,当它们执行完成后会发出信号。一旦第二
个线程完成,主线程会从等待CountdownEvent的状态中返回并继续执行。针对需要等待多
个异步操作完成的情形,使用该方式是非常便利的。
然而这有一个重大的缺点。如果调用countdown.Signal()没达到指定的次数,那么
countdown.Wait()将一直等待。请确保使用CountdownEvent时,所有线程完成后都要调用
Signal方法。
使用Barrier类
本节将展示另一种有意思的同步方式,被称为BarrieroBamer类用于组织多个线程及时
在某个时刻碰面。其提供了一个回调函数,每次线程调用了SignalAndWait方法后该回调函
数会被执行。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace 使用Barrier类
{
internal class Program
{
static Barrier _barrier = new Barrier(2, b => Console.WriteLine("End of phase{0}", b.CurrentPhaseNumber + 1));
static void PlayMusic(string name,string message,int seconds)
{
Console.WriteLine("--------------------------------");
Thread.Sleep(TimeSpan.FromSeconds(seconds));
Console.WriteLine("{0}starts to {1}", name, message);
Thread.Sleep(TimeSpan.FromSeconds(seconds));
Console.WriteLine("{0} finishes to {1}", name, message);
_barrier.SignalAndWait();
}
static void Main(string[] args)
{
var t1 = new Thread(() => PlayMusic("the guitarist", "play an amazing solo", 5));
var t2 = new Thread(() => PlayMusic("the singer", "sing his song", 2));
t1.Start();
t2.Start();
}
}
}
运行结果
--------------------------------
--------------------------------
the singerstarts to sing his song
the singer finishes to sing his song
the guitariststarts to play an amazing solo
the guitarist finishes to play an amazing solo
End of phase1
工作原理
我们创建了Bamer类,指定了我们想要同步两个线程。在两个线程中的任何一个调用
了bamer.SignalAndWait方法后,会执行一个回调函数来打印出阶段。
每个线程将向Barrier“发送两次信号,所以会有两个阶段每次这两个线程调用Signal
AndWait方法时,Bamer将执行回调函数。这在多线程迭代运算中非常有用,可以在每个迭代
结束前执行一些计算。当最后一个线程调用SignalAndWait方法时可以在迭代结束时进行交互。
更多推荐
所有评论(0)