在回顾一下,前段时间使用过忘记了。

AutoResetEvent类

通知正在等待的线程已发生事件,此类不能被继承

主要使用的方法有两个:

  1. Set()

将事件设置为终止状态,允许一个或多个等待线程继续

  1. WaitOne()
    阻止当前线程,直至当前WaitHandle收到信号,其实就是收到Set信号

在构造函数中可以使用bool来决定一开始是终止的还是非终止的。

栗子

class HeiSheHhui
    {
        private static AutoResetEvent startSighal = new AutoResetEvent(false);

        public static void Test()
        {
            Thread xiaodiThread = new Thread(ThreadProc);
            xiaodiThread.Start();
            for (int i = 0; i < 2; i++)
            {
                Console.ReadLine();
                startSighal.Set();
            }
            Console.WriteLine("结束");
            Console.ReadKey();
        }
        
        static void ThreadProc()
        {
            Console.WriteLine("小弟们都已经准备好了,就等老大发话了。。。。按回车我们就上");
            startSighal.WaitOne();
            Console.WriteLine("兄弟们上啊");
            Console.WriteLine("小弟们又准备好了,就等老大发话了。。。。按回车我们就上,再打一次");
            startSighal.WaitOne();
            Console.WriteLine("兄弟们上啊");
        }
    }

举一个黑社会的例子,只有收到Set信号后,小弟们才会冲上去,否则会原地等待。
运行结果

这样就可以开控制线程里面的状态了。

CancellationTokenSource 类

向应该被取消的CancellationToken发送信号

主要用到的是:

  1. 构造函数可以指定延迟时间传达取消信号
    CancellationTokenSource()CancellationTokenSource(Int32)

  2. Cancel()
    传达取消请求

  3. IsCancellationRequested()
    看看是不是已经取消了

栗子

class Example
    {
        static CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();

        public static void Test()
        {
            Thread thread = new Thread(new ThreadStart(() =>
            {
                while (!cancellationTokenSource.IsCancellationRequested)
                {
                    Console.WriteLine("还在执行。。。。");
                    Thread.Sleep(1000);
                }
                Console.WriteLine("好,执行完成了");
            }));
            thread.Start();

            Console.WriteLine("按回车键发送信号取消线程的执行。。。。");
            Console.ReadLine();
            cancellationTokenSource.Cancel();
            Console.WriteLine("取消了。。。");
            Console.ReadLine();
        }
    }

运行结果

System.Collections.Consurrent命名空间

System.Collections.Concurrent命名空间提供多个线程安全集合类,当有多个线程并发访问集合时,应使用这些类代替System.CollectionsSystem.Collections.Generic命名空间中的对应类型

经常使用的类

  1. BlockingCollection<T>
    为实现IProducerConsumerCollection<T>的线程安全集合提供阻塞和限制功能

  2. ConcurrentBag<T>
    线程安全的对象无序集合,包

  3. ConcurrentDictionary<TKey,TValue>ConcurrentQueue<T>ConcurrentStack<T>
    从名字中就能看出来是字典、队列和栈

ConcurrentQuent 栗子

class CQ_EnqueueDequeuePeek
{
    // Demonstrates:
    // ConcurrentQueue<T>.Enqueue()
    // ConcurrentQueue<T>.TryPeek()
    // ConcurrentQueue<T>.TryDequeue()
    public static void Test()
    {
        // Construct a ConcurrentQueue.
        ConcurrentQueue<int> cq = new ConcurrentQueue<int>();

        // Populate the queue.
        for (int i = 0; i < 10000; i++) cq.Enqueue(i);

        // Peek at the first element.
        int result;
        if (!cq.TryPeek(out result))
        {
            Console.WriteLine("CQ: TryPeek failed when it should have succeeded");
        }
        else if (result != 0)
        {
            Console.WriteLine("CQ: Expected TryPeek result of 0, got {0}", result);
        }

        int outerSum = 0;
        // An action to consume the ConcurrentQueue.
        Action action = () =>
        {
            int localSum = 0;
            int localValue;
            while (cq.TryDequeue(out localValue)) localSum += localValue;
            //为多个线程共享的变量提供原子操作
            Interlocked.Add(ref outerSum, localSum);
        };

        // Start 4 concurrent consuming actions.
        Parallel.Invoke(action, action, action, action);

        Console.WriteLine("outerSum = {0}, should be 49995000", outerSum);
    }
}

Action的用法和几个多线程时需要用的操作。