C# 多线程通讯详解

1、WaitHandler的类层次

image

能够看到 WaitHandle是 事件(EventWaitHandle)、互斥体(Mutex)、信号量(Sempahore)的父类。spa

image

 

image

 

WaitHandle咱们最常常使用的方法,并是使用它的静态方法WaitAll. 咱们会发如今这个WaitHandle里面只有等待方法,也就是它会阻塞当前线程的执行。线程

那么如何要解除它对当前线程的阻塞呢,那么就须要依赖于各个子类的方法了。3d

image

image

image

 

例如如今有一个这样的场景,如何在一个方法中,等待全部的线程所有执行完,最后再统计获得的计算结果呢?code

WaitHandle[] handlers = new WaitHandle[]{
  new AutoResetEvent(false),
  new AutoResetEvent(false),
  new AutoResetEvent(false),
  new AutoResetEvent(false),
  new AutoResetEvent(false),
  new AutoResetEvent(false),
  new AutoResetEvent(false),
  new AutoResetEvent(false)
};

for (var i = 0; i < handlers.Length; i++)
{
    ThreadPool.QueueUserWorkItem(ar =>
    {
        int index = (int)ar;
        Thread.Sleep(1000);
        AppCenter.AppendLog("任务:" + index + "开始执行!");
        (handlers[index] as AutoResetEvent).Set();
    }, i);
}

ThreadPool.QueueUserWorkItem(ar =>
{
    WaitHandle.WaitAll(handlers);
    AppCenter.AppendLog("全部任务都已经完成了,我不用再等待了。");
});
运行结果以下:

image

2、EventWaitHandle

image

这个方法,能够方便实现两个线程之间的相互通讯。blog

如何实现两个线程的相互通讯?事件

EventWaitHandle handleA = new AutoResetEvent(false);
EventWaitHandle handleB = new AutoResetEvent(false);

ThreadPool.QueueUserWorkItem(ar =>
{
    AppCenter.AppendLog("A:我是A,我已经开始运行了");
    Thread.Sleep(2000);
    AppCenter.AppendLog("A:我想睡觉了,B你先跑跑吧。");
    EventWaitHandle.SignalAndWait(handleB, handleA);
    AppCenter.AppendLog("A:开始工做ing");
    Thread.Sleep(3000);
    AppCenter.AppendLog("A:这个有点难,问下B");
    EventWaitHandle.SignalAndWait(handleB, handleA);
    AppCenter.AppendLog("A:不错,今天任务搞定,我也闪人了。");
});

ThreadPool.QueueUserWorkItem(ar =>
{
    handleB.WaitOne();
    AppCenter.AppendLog("B:我是B,我已经顶替A开始运行了。");
    Thread.Sleep(5000);
    AppCenter.AppendLog("B:个人事情已经作完了,该让A搞搞了,休息一会。");
    EventWaitHandle.SignalAndWait(handleA, handleB);
    AppCenter.AppendLog("B:hi,A我搞定了,下班了。");
    handleA.Set();
});
运行结果以下:

image

 

那么AutoResetEvent和ManualResetEvent有什么区别呢?咱们先作个实验。get

private EventWaitHandle manualEvent = new ManualResetEvent(false);

private void ManualResetEvent_Click(object sender, EventArgs e)
{   

    AppCenter.CleanLogs();

    ThreadPool.QueueUserWorkItem(ar =>
    {
        int i = 0;
        while (true)
        {
            manualEvent.WaitOne();  //ManualResetEvent的Set()方法,让事件的终止状态永远为true,让这里一直能执行。             i++;                    //而AutoResetEvent的Set()方法,初始化让这里执行一次,而后再次执行时是非终止的。将阻塞原有线程的执行
            AppCenter.AppendLog("#" + i.ToString());
            Thread.Sleep(1000);
        }
    });
}

private void button2_Click(object sender, EventArgs e)
{
    manualEvent.Set();
}

private void button3_Click(object sender, EventArgs e)
{
    manualEvent.Reset();
}

运行结果it

image

咱们会发现ManualResetEvent在触发Set()方法会,解除了原有的线程的 WaitOne方法,会一直打印输出。class

而当咱们替换为AutoResetEvent方法时候。object

image

 

此时每次只会打印一个输出。由于它将 事件的状态设置为终止后,又变为了false.

 

3、Semaphore 控制并行线程的执行

应用场景,若是有多个线程跑,我可否每次控制3个线程一块儿跑呢。

Semaphore sempore = new Semaphore(0, 3);
for (int i = 0; i < 8; i++)
{
    ThreadPool.QueueUserWorkItem(ar =>
    {
        sempore.WaitOne();
        AppCenter.AppendLog("\t第:" +((int)ar).ToString() + "个开始运行.");
    },i);
}
ThreadPool.QueueUserWorkItem(ar =>
{
    for (int i = 0; i < 3; i++)
    {
        AppCenter.AppendLog("" + (i + 1).ToString() + "批开始执行.");
        sempore.Release(3);
        Thread.Sleep(5000);
    }
});

运行结果:

image

相关文章
相关标签/搜索