C#粗谈线程处理对象和功能

      最近在学习线程同步的一些东西,发现这里面的水很深,边看MSDN边查各种博客边写Demo,却只是略懂皮毛,先做一下记录,以后慢慢补充,先给出一些网站,关于线程对象的资料:

     1. (MSDN)线程处理对象列表   这里面有ThreadPool、BackgroundWorker、Monitor、WaitHandle、EventWaitHandle、AutoRetsetEvent、ManualResetEvent、Mutex等线程处理对象的介绍,每个连接点开,就是每个对象的详细解释,然后再详细解释页面再点开就是每个对象的属性、时间、方法、示例等,很详细。

     2. 写个自己的博客之线程同步系列博客五篇  这是其他人对这些东西的领悟,比我要深很多,记录。

     3. (CSDN)码农时代的线程同步博客

    我对这几个对象理解很浅,大家可以看下,然后再看上面这几个,便于理解,顺便有什么说的不对的地方,可以帮忙批评指正一下。

第一个,ThreadPool:

    线程池ThreadPool:主要用到的方法就是QueueUserWorkItem(WaitCallback, Object), 它把一个工作线程放进队列中,进行排队以便于进行执行。

    关于ThreadPool的详细信息,查看这里ThreadPool

第二个, BackgroundWorker:

    前几天刚写了一篇关于这个组件的用法,点击这里.

第三个, Monitor:

    监视器Monitor主要有以下几个方法:Enter、Exit、TryEnter、Wait、Pulse、PulseAll,解释如下:

    Monitor 对象通过使用 Monitor.Enter  Monitor.TryEnterMonitor.Exit 方法对特定对象进行加锁和解锁来提供同步访问代码区域的功能。 对代码区域加  锁之后,可以使用 Monitor.WaitMonitor.PulseMonitor.PulseAll 方法。 Wait 在其暂停并等待通知的情况下解锁。 Wait 收到通知时,会返回并重新加锁。 PulsePulseAll 都发送信号以继续执行等待队列中的下一个线程。

其中,Monitor的Enter方法和Exit方法是成对出现,调用了多少次Enter就要调用多少次Exit,不然会出现异常。且,

Monitor.Enter();
try
{
     //
}
Finally
{
     Monitor.Exit();
}

等价于:

private static ReadOnly object syncObj = new object();

lock(syncObj)
{
     //
}

                          **¥**¥**¥**¥**¥**¥**¥**¥**¥**¥**¥**¥**¥**¥**¥**¥**¥**¥**¥**¥**¥**¥**¥**

对于WaitHandle、EventWaitHandle、AutoRetsetEvent、ManualResetEvent、Mutex用家族树的方法来看就是: WaitHandle是爷爷辈的一棵独苗,然后生了两个孩子EventWaitHandle和Mutex, 然后Mutex打了光棍,EventWaitHandle生了两个孩子AutoRetsetEvent和ManualResetEvent。

祖辈,WaitHandle:

线程可以通过调用实例方法 WaitOne 在单个等待句柄上阻塞。 此外,WaitHandle 类重载了静态方法,以等待所有指定的等待句柄集都已收到信号 (WaitAll),或等待某一指定的等待句柄集收到信号 (WaitAny)。 这些方法的重载提供了放弃等待的超时间隔、在进入等待之前退出同步上下文的机会,并允许其他线程使用同步上下文。

在 .NET Framework 2.0 版中,等待句柄还具有静态 SignalAndWait 方法,它允许线程发送一个等待句柄信号并立即等待另一个。(MSDN中原话,我没这么牛逼)

这里主要讲一下SignalAndWait(WaitHandle, WaitHandle):MSND对它的解释是向一个 WaitHandle 发出信号并等待另一个。 这个把我晕了很久,后来多次测试分析发现就是:

        WaitHandle ewh = null;
        long threadCount;
        WaitHandle countClear = new EventWaitHandle(false, EventResetMode.AutoReset);

        private void DoThreadsTask()
        {
            ewh = new EventWaitHandle(false, EventResetMode.AutoReset);
            Thread t = new Thread(ExcuteThreadTask);
            t.Start(1);
            while (Interlocked.Read(ref threadCount) < 1)
            {
                Thread.Sleep(1000);
            }

            while (Interlocked.Read(ref threadCount) > 0)
            {
                Trace.WriteLine("Release a waiting thread.");
                WaitHandle.SignalAndWait(ewh, countClear);
            }
            Trace.WriteLine("Press ENTER to release the waiting threads.");
        }

        private void ExcuteThreadTask(object obj)
        {
            int index = (int)obj;
            Trace.WriteLine(string.Format("Thread {0} blocks.", index));
            Interlocked.Increment(ref threadCount);
            Trace.WriteLine("1当前值为:" + threadCount);
            ewh.WaitOne();
            Trace.WriteLine(string.Format("Thread {0} exits.", index));
            Interlocked.Decrement(ref threadCount);
            Trace.WriteLine("2当前值为:" + threadCount);
            countClear.Set();
        }

       public delegate void StartThreadsHandler();
        private void btnStart_Click(object sender, EventArgs e)
        {
            StartThreadsHandler handler = DoThreadsTask;
            handler.BeginInvoke(null, null);
        }

简单来说就是:两个WaitHandle的实例A、B,A在工作线程调用了A.WaitOne(), B没有做任何操作,然后调用静态方法WaitHandle.SignalAndWait(A, B)等价于:A.Set();

B.WaitOne();两个方法。

父辈之光棍,Mutex:

       主要用法可以控制应用程序只开启一个,当前不关闭,无法再打开另外一个,参考这里

父辈EventWaitHandle和孙辈AutoResetEvent、ManualResetEvent:

AutoResetEvent的功能等价于 EventWaitHandle(false, EventResetMode.AutoReset), 而ManualResetEvent的功能等价于 EventWaitHandle(false, EventResetMode.ManualReset) 。

MSDN中的说法:

EventWaitHandle 类可以表示自动或手动重置事件以及本地事件或命名系统事件。

AutoResetEvent 类派生自 EventWaitHandle,表示自动重置的本地事件。

ManualResetEvent 类派生自 EventWaitHandle,表示必须手动重置的本地事件。

对于孙子辈的这两个对象的执行过程,我的理解是:打个比方,在羊圈中有10头羊(10个工作线程),如果羊圈门AutoResetEvent ARE, ARE = new AutoResetEvent(false)表示羊圈门是关着的,调用ARE.Set()表示门打开,一只羊出来(工作线程被阻塞结束,可以继续执行),然后门自动关闭(ARE.Reset()),调用调用ARE.Set()表示门打开,第二只羊出来... AutoResetEvent(true)表示羊圈门是开着的,即使调用ARE.WaitOne(),门依旧开着,出来一只羊,门自动关闭,需要调用ARE.Set()打开门....   如果羊圈门ManualResetEvent MRE,MRE = new ManualResetEvent(true)表示门是打开着的,第一只羊出来,接着第二只,如果不调用MRE.Reset()则门一直开着,不会自动关闭,反之,MRE = new ManualResetEvent(false)表示门是关着的,调用MRE.Set()则门一直打开,除非手动调用MRE.Reset().....例子就不写了,参考MSDN吧。

原文地址:https://www.cnblogs.com/yuqf/p/3096548.html