读书人

c#线程同步跟交互

发布时间: 2013-04-09 16:45:09 作者: rapoo

c#线程同步和交互

// 版权所有 (C) Microsoft Corporation。保留所有权利。using System;using System.Threading;using System.Collections;using System.Collections.Generic;// 将线程同步事件封装在此类中, // 以便于将这些事件传递给 Consumer 和// Producer 类。public class SyncEvents{    public SyncEvents()    {        // AutoResetEvent 用于“新项”事件,因为        // 我们希望每当使用者线程响应此事件时,        // 此事件就会自动重置。        _newItemEvent = new AutoResetEvent(false);        // ManualResetEvent 用于“退出”事件,因为        // 我们希望发出此事件的信号时有多个线程响应。        // 如果使用 AutoResetEvent,事件        // 对象将在单个线程作出响应之后恢复为         // 未发信号的状态,而其他线程将        // 无法终止。        _exitThreadEvent = new ManualResetEvent(false);        // 这两个事件也放在一个 WaitHandle 数组中,以便        // 使用者线程可以使用 WaitAny 方法        // 阻塞这两个事件。        _eventArray = new WaitHandle[2];        _eventArray[0] = _newItemEvent;        _eventArray[1] = _exitThreadEvent;    }    // 公共属性允许对事件进行安全访问。    public EventWaitHandle ExitThreadEvent    {        get { return _exitThreadEvent; }    }    public EventWaitHandle NewItemEvent    {        get { return _newItemEvent; }    }    public WaitHandle[] EventArray    {        get { return _eventArray; }    }    private EventWaitHandle _newItemEvent;    private EventWaitHandle _exitThreadEvent;    private WaitHandle[] _eventArray;}// Producer 类(使用一个辅助线程)// 将项异步添加到队列中,共添加 20 个项。public class Producer {    public Producer(Queue<int> q, SyncEvents e)    {        _queue = q;        _syncEvents = e;    }    public void ThreadRun()    {        int count = 0;        Random r = new Random();        while (!_syncEvents.ExitThreadEvent.WaitOne(0, false))        {            lock (((ICollection)_queue).SyncRoot)            {                while (_queue.Count < 20)                {                    _queue.Enqueue(r.Next(0, 100));                    _syncEvents.NewItemEvent.Set();                    count++;                }            }        }        Console.WriteLine("Producer thread: produced {0} items", count);    }    private Queue<int> _queue;    private SyncEvents _syncEvents;}// Consumer 类通过自己的辅助线程使用队列// 中的项。Producer 类使用 NewItemEvent // 将新项通知 Consumer 类。public class Consumer{    public Consumer(Queue<int> q, SyncEvents e)    {        _queue = q;        _syncEvents = e;    }    public void ThreadRun()    {        int count = 0;        while (WaitHandle.WaitAny(_syncEvents.EventArray) != 1)        {            lock (((ICollection)_queue).SyncRoot)            {                int item = _queue.Dequeue();            }            count++;        }        Console.WriteLine("Consumer Thread: consumed {0} items", count);    }    private Queue<int> _queue;    private SyncEvents _syncEvents;}public class ThreadSyncSample{    private static void ShowQueueContents(Queue<int> q)    {        // 对集合进行枚举本来就不是线程安全的,        // 因此在整个枚举过程中锁定集合以防止        // 使用者和制造者线程修改内容        // 是绝对必要的。(此方法仅由        // 主线程调用。)        lock (((ICollection)q).SyncRoot)        {            foreach (int i in q)            {                Console.Write("{0} ", i);            }        }        Console.WriteLine();    }    static void Main()    {        // 配置结构,该结构包含线程同步        // 所需的事件信息。        SyncEvents syncEvents = new SyncEvents();        // 泛型队列集合用于存储要制造和使用的        // 项。此例中使用的是“int”。        Queue<int> queue = new Queue<int>();        // 创建对象,一个用于制造项,一个用于        // 使用项。将队列和线程同步事件传递给        // 这两个对象。        Console.WriteLine("配置工作线程...");        Producer producer = new Producer(queue, syncEvents);        Consumer consumer = new Consumer(queue, syncEvents);        // 为制造者对象和使用者对象创建线程        // 对象。此步骤并不创建或启动        // 实际线程。        Thread producerThread = new Thread(producer.ThreadRun);        Thread consumerThread = new Thread(consumer.ThreadRun);        // 创建和启动两个线程。        Console.WriteLine("Launching producer and consumer threads...");                producerThread.Start();        consumerThread.Start();        // 为制造者线程和使用者线程设置 10 秒的运行时间。        // 使用主线程(执行此方法的线程)        // 每隔 2.5 秒显示一次队列内容。        for (int i = 0; i < 4; i++)        {            Thread.Sleep(2500);            ShowQueueContents(queue);        }        // 向使用者线程和制造者线程发出终止信号。        // 这两个线程都会响应,由于 ExitThreadEvent 是        // 手动重置的事件,因此除非显式重置,否则将保持“设置”。        Console.WriteLine("Signaling threads to terminate...");        //将事件状态设置成终止状态,允许一个或者多个等待线程继续。        syncEvents.ExitThreadEvent.Set();        // 使用 Join 阻塞主线程,首先阻塞到制造者线程        // 终止,然后阻塞到使用者线程终止。        Console.WriteLine("main thread waiting for threads to finish...");        producerThread.Join();        consumerThread.Join();    }}

读书人网 >C#

热点推荐