天天看点

多线程-3(同步)

SemaphoreSlim类

代码:

View Code

多线程-3(同步)

 主线程启动,创建SemaphoreSlim的一个实例,在构造函数中指定允许并发线程数量,启动6个不同名称和不同初始运行时间的线程,借助信号系统限制访问数据的并发数, 只允许4个线程获取, 注意:.当线程1完成后,线程0才进行授权访问。

AutoResetEven类

多线程-3(同步)

AutoResetEvent类采用的是内核时间模式,所以等待时间不能太长。使用ManualResetEventslim类更好。

ManualResetEventSlim类

static ManualResetEventSlim mainEvent = new ManualResetEventSlim(false);

static void TravleThroughGates(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);

}

static void Main(string[] args)

var t1 = new Thread(() => TravleThroughGates("threadName 1", 5));

var t2 = new Thread(() => TravleThroughGates("threadName 2", 6));

var t3 = new Thread(() => TravleThroughGates("threadName 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.Reset();//将事件状态设置为非终止,从而导致线程受阻

Console.WriteLine("The gates have been closed!");

Thread.Sleep(TimeSpan.FromSeconds(10));

Console.WriteLine("The gates are now open for the seconds time!");

mainEvent.Set();

mainEvent.Reset();

这里启动了三个线程,同时进行等待。ManualResetEventSlim 的set是允许准备好的线程接受信号并继续工作。

CountDownEvent类

CountDownEvent信号类来等待直到一定数量的操作完成。

static CountdownEvent countdownEvent = new CountdownEvent(2);

static void PerformOperation(string message,int seconds)

Console.WriteLine(message);

countdownEvent.Signal();

Console.WriteLine("Starting two operations");

var t1 = new Thread(() => PerformOperation("Operation 1 is completd", 4));

var t2 = new Thread(() => PerformOperation("Operation 2 is completd", 8));

countdownEvent.Wait();

Console.WriteLine("Both operation have been completd");

countdownEvent.Dispose();

多线程-3(同步)

启动两个线程,当它们执行完成后会发生信号。一旦第二个线程完成,主程序会从等待CountdownEvent的状态中返回并继续执行。当针对需要等待多个异步操作的情形,方法非常遍历。当然如果某个线程出现死锁等情况,一直等待下,那么会一直等待。

Barrier类

Barrier类组织多个线程及时在某个时刻碰面。并提供了一个回调函数,每次线程调用了SignalAndWait方法后该回调函数会执行

static Barrier barrier = new Barrier(2, b => Console.WriteLine("End of phase {0}", b.CurrentPhaseNumber + 1));

static void PlayMusic(string name,string messages,int seconds)

for (int i = 0; i < 3; i++)

{

Console.WriteLine("-----------------------------");

Thread.Sleep(TimeSpan.FromSeconds(seconds));

Console.WriteLine("{0} starts to {1}", name, messages);

Console.WriteLine("{0} finshes to {1}", name, messages);

barrier.SignalAndWait();

}

var t1 = new Thread(() => PlayMusic("the guitarist", "play an amazing solo", 5));

var t2 = new Thread(() => PlayMusic("the singer", "sing his song", 2));

使用Barrier,指定我们想同步两个线程。这两个线程任意一个调用了SignalAndWait方法后,会执行一个回调来打印出阶段

多线程-3(同步)

ReaderWriterLockSlim

ReaderWriterLockSlim类来创建一个线程安全的机制,在多线程中对一个集合进行读写操作。ReaderWriterLockSlim代表一个管理资源访问的锁,允许多个线程同时读取,以及独占写。

多线程-3(同步)

同时运行了三个程序来从字典中读取数据,还有另外两个线程向该字典中写入数据,使用ReaderWriterLockSlim类实现线程安全。

这里使用两种锁:读锁允许多线程读取数据,写锁在被释放前会阻塞了其他线程的所有操作,先获取读锁后读取数据,如果发现必须修改底层集合,只需使用EnterWriterLock方法升级锁,然后快速执行写操作。

SpanWait类

如果不使用内核模型的方式来使线程等待。SpanWait是一个混合同步结构,设计为使用用户模式等待一段时间,然后切换到内核模式以节省CPU时间

static volatile bool isCompleted = false;//volatile允许多个线程访问,呈现最新的

static void UserModelWait()

while(!isCompleted)

Console.WriteLine(".");

Console.WriteLine("Waiting is complete");

static void HybridSpinWait()

var w = new SpinWait();

while (!isCompleted)

w.SpinOnce();

Console.WriteLine(w.NextSpinWillYield);

var t1 = new Thread(UserModelWait);

var t2 = new Thread(HybridSpinWait);

Console.WriteLine("Running user mode waiting");

Thread.Sleep(20);

isCompleted = true;

Thread.Sleep(TimeSpan.FromSeconds(1));

isCompleted = false;

Console.WriteLine("Running hybrid SpinWait construct waiting");

Thread.Sleep(5);

多线程-3(同步)

定义一个线程,将执行一个无止境的循环,直到20毫秒后主线程设置isCompleted变量为true,我们可以试验周期为20-30秒,通过windows任务管理器测量CPU的负载情况。

用volatie关键字来声明iscompleted静态字段,volatie字段不会被编辑器和处理器优化,只能被单个线程访问。

继续阅读