C#读写者线程(用AutoResetEvent实现同步)

时间:2014-04-28 01:39:37   收藏:0   阅读:764

转载自 http://blog.csdn.net/livelylittlefish/article/details/2735440

 

本博客(http://blog.csdn.net/livelylittlefish)贴出作者(三二一、小鱼)相关研究、学习内容所做的笔记,欢迎广大朋友指正!

 

C#读写者线程(用AutoResetEvent实现同步)

 

 

1. AutoResetEvent简介

 

通知正在等待的线程已发生事件。无法继承此类。

 

常用方法简介:

    false:无信号,子线程的WaitOne方法不会被自动调用     true:有信号,子线程的WaitOne方法会被自动调用

    对于具有 EventResetMode.AutoReset(包括 AutoResetEvent)的 EventWaitHandle,Set 方法释放单个线程。如果没有等待线程,等待句柄将一直保持终止状态,直到某个线程尝试等待它,或者直到它的 Reset 方法被调用。

 

    对于具有 EventResetMode.ManualReset(包括 ManualResetEvent)的 EventWaitHandle,调用Set 方法将使等待句柄一直保持终止状态,直到它的 Reset 方法被调用。

 

       当在派生类中重写时,阻止当前线程,直到当前的 WaitHandle 收到信号。

  1. WaitHandle.WaitOne () 当在派生类中重写时,阻止当前线程,直到当前的 WaitHandle 收到信号。 由.NET Compact Framework 支持。
  2. WaitHandle.WaitOne(Int32, Boolean)  在派生类中被重写时,阻止当前线程,直到当前的WaitHandle 收到信号,使用 32 位有符号整数度量时间间隔并指定是否在等待之前退出同步域。由 .NET Compact Framework 支持。
  3. WaitHandle.WaitOne(TimeSpan, Boolean)  在派生类中被重写时,阻止当前线程,直到当前实例收到信号,使用 TimeSpan 度量时间间隔并指定是否在等待之前退出同步域。

2. 读写者线程例子

 

本例子中,主线程作为写线程,要对某个数据(本例中是个变量)赋值(即写动作),而读线程则等待写线程每次写完数据发出通知,待读线程收到通知后,将数据读出并显示。

  1. using System; 
  2. using System.Collections.Generic; 
  3. using System.Text; 
  4.  
  5. using System.Threading; 
  6.  
  7. namespace TestAutoResetEvent 
  8.     /// <summary> 
  9.     /// 读写者线程 
  10.     /// 主线程写,子线程读,且只有将数据写入后,读线程才能将其读出 
  11.     /// </summary> 
  12.     class Program 
  13.     { 
  14.         //写线程将数据写入myData 
  15.         staticint myData = 100; 
  16.  
  17.         //读写次数 
  18.         constint readWriteCount = 10; 
  19.  
  20.         //false:初始时没有信号 
  21.         static AutoResetEvent autoResetEvent = new AutoResetEvent(false); 
  22.  
  23.         staticvoid Main(string[] args) 
  24.         { 
  25.             //开启一个读线程(子线程) 
  26.             Thread readerThread = new Thread(new ThreadStart(ReadThreadProc)); 
  27.             readerThread.Name = "ReaderThread"
  28.             readerThread.Start(); 
  29.  
  30.             for (int i = 1; i <= readWriteCount; i++) 
  31.             { 
  32.                 Console.WriteLine("MainThread writing : {0}", i); 
  33.  
  34.                 //主(写)线程将数据写入 
  35.                 myData = i; 
  36.  
  37.                 //主(写)线程发信号,说明值已写过了 
  38.                 //即通知正在等待的线程有事件发生 
  39.                 autoResetEvent.Set(); 
  40.  
  41.                 Thread.Sleep(0); 
  42.             } 
  43.  
  44.             //终止线程 
  45.             readerThread.Abort(); 
  46.         } 
  47.  
  48.         staticvoid ReadThreadProc() 
  49.         { 
  50.             while (true
  51.             { 
  52.                 //在数据被写入前,读线程等待(实际上是等待写线程发出数据写完的信号) 
  53.                 autoResetEvent.WaitOne(); 
  54.                 Console.WriteLine("{0} reading : {1}", Thread.CurrentThread.Name, myData); 
  55.             } 
  56.         } 
  57.     } 
  58. }<pre></pre> 
using System;
using System.Collections.Generic;
using System.Text;

using System.Threading;

namespace TestAutoResetEvent
{
    ///
    /// 读写者线程
    /// 主线程写,子线程读,且只有将数据写入后,读线程才能将其读出
    ///
    class Program
    {
        //写线程将数据写入myData
        static int myData = 100;

        //读写次数
        const int readWriteCount = 10;

        //false:初始时没有信号
        static AutoResetEvent autoResetEvent = new AutoResetEvent(false);

        static void Main(string[] args)
        {
            //开启一个读线程(子线程)
            Thread readerThread = new Thread(new ThreadStart(ReadThreadProc));
            readerThread.Name = "ReaderThread";
            readerThread.Start();

            for (int i = 1; i <= readWriteCount; i++)
            {
                Console.WriteLine("MainThread writing : {0}", i);

                //主(写)线程将数据写入
                myData = i;

                //主(写)线程发信号,说明值已写过了
                //即通知正在等待的线程有事件发生
                autoResetEvent.Set();

                Thread.Sleep(0);
            }

            //终止线程
            readerThread.Abort();
        }

        static void ReadThreadProc()
        {
            while (true)
            {
                //在数据被写入前,读线程等待(实际上是等待写线程发出数据写完的信号)
                autoResetEvent.WaitOne();
                Console.WriteLine("{0} reading : {1}", Thread.CurrentThread.Name, myData);
            }
        }
    }
}

运行结果如下:

 

 

bubuko.com,布布扣

 

由运行结果可以看出,写线程写入的数据有丢失,主要原因是写线程没有给读线程留足够的时间去进行读操作。

 

3. 对1进行修改

将主线程睡眠时间改为非0值,观察运行结果。

  1. using System; 
  2. using System.Collections.Generic; 
  3. using System.Text; 
  4.  
  5. using System.Threading; 
  6.  
  7. namespace TestAutoResetEvent 
  8.     /// <summary> 
  9.     /// 读写者线程 
  10.     /// 主线程写,子线程读,且只有将数据写入后,读线程才能将其读出 
  11.     /// </summary> 
  12.     class Program 
  13.     { 
  14.         //写线程将数据写入myData 
  15.         staticint myData = 100; 
  16.  
  17.         //读写次数 
  18.         constint readWriteCount = 10; 
  19.  
  20.         //false:初始时没有信号 
  21.         static AutoResetEvent autoResetEvent = new AutoResetEvent(false); 
  22.  
  23.         staticvoid Main(string[] args) 
  24.         { 
  25.             //开启一个读线程(子线程) 
  26.             Thread readerThread = new Thread(new ThreadStart(ReadThreadProc)); 
  27.             readerThread.Name = "ReaderThread"
  28.             readerThread.Start(); 
  29.  
  30.             for (int i = 1; i <= readWriteCount; i++) 
  31.             { 
  32.                 Console.WriteLine("MainThread writing : {0}", i); 
  33.  
  34.                 //主(写)线程将数据写入 
  35.                 myData = i; 
  36.  
  37.                 //主(写)线程发信号,说明值已写过了 
  38.                 //即通知正在等待的线程有事件发生 
  39.                 autoResetEvent.Set(); 
  40.  
  41.                 Thread.Sleep(1); 
  42.             } 
  43.  
  44.             //终止线程 
  45.             readerThread.Abort(); 
  46.         } 
  47.  
  48.         staticvoid ReadThreadProc() 
  49.         { 
  50.             while (true
  51.             { 
  52.                 //在数据被写入前,读线程等待(实际上是等待写线程发出数据写完的信号) 
  53.                 autoResetEvent.WaitOne(); 
  54.                 Console.WriteLine("{0} reading : {1}", Thread.CurrentThread.Name, myData); 
  55.             } 
  56.         } 
  57.     } 
using System;
using System.Collections.Generic;
using System.Text;

using System.Threading;

namespace TestAutoResetEvent
{
    /// 
    /// 读写者线程
    /// 主线程写,子线程读,且只有将数据写入后,读线程才能将其读出
    /// 
    class Program
    {
        //写线程将数据写入myData
        static int myData = 100;

        //读写次数
        const int readWriteCount = 10;

        //false:初始时没有信号
        static AutoResetEvent autoResetEvent = new AutoResetEvent(false);

        static void Main(string[] args)
        {
            //开启一个读线程(子线程)
            Thread readerThread = new Thread(new ThreadStart(ReadThreadProc));
            readerThread.Name = "ReaderThread";
            readerThread.Start();

            for (int i = 1; i <= readWriteCount; i++)
            {
                Console.WriteLine("MainThread writing : {0}", i);

                //主(写)线程将数据写入
                myData = i;

                //主(写)线程发信号,说明值已写过了
                //即通知正在等待的线程有事件发生
                autoResetEvent.Set();

                Thread.Sleep(1);
            }

            //终止线程
            readerThread.Abort();
        }

        static void ReadThreadProc()
        {
            while (true)
            {
                //在数据被写入前,读线程等待(实际上是等待写线程发出数据写完的信号)
                autoResetEvent.WaitOne();
                Console.WriteLine("{0} reading : {1}", Thread.CurrentThread.Name, myData);
            }
        }
    }
}

运行结果如下:

 

bubuko.com,布布扣

 

有结果可知,当主线程睡眠时间大于0值时,读线程即有足够的时间读取写线程写入的数据。这个睡眠时间的长短可以根据实际应用中子线程的计算量设定。

 

4. 对1再进行修改

主线程在写完数据后根本不睡吗呢?这个时候会发生什么事情?

  1. using System; 
  2. using System.Collections.Generic; 
  3. using System.Text; 
  4.  
  5. using System.Threading; 
  6.  
  7. namespace TestAutoResetEvent 
  8.     /// <summary> 
  9.     /// 读写者线程 
  10.     /// 主线程写,子线程读,且只有将数据写入后,读线程才能将其读出 
  11.     /// </summary> 
  12.     class Program 
  13.     { 
  14.         //写线程将数据写入myData 
  15.         staticint myData = 100; 
  16.  
  17.         //读写次数 
  18.         constint readWriteCount = 10; 
  19.  
  20.         //false:初始时没有信号 
  21.         static AutoResetEvent autoResetEvent = new AutoResetEvent(false); 
  22.  
  23.         staticvoid Main(string[] args) 
  24.         { 
  25.             //开启一个读线程(子线程) 
  26.             Thread readerThread = new Thread(new ThreadStart(ReadThreadProc)); 
  27.             readerThread.Name = "ReaderThread"
  28.             readerThread.Start(); 
  29.  
  30.             for (int i = 1; i <= readWriteCount; i++) 
  31.             { 
  32.                 Console.WriteLine("MainThread writing : {0}", i); 
  33.  
  34.                 //主(写)线程将数据写入 
  35.                 myData = i; 
  36.  
  37.                 //主(写)线程发信号,说明值已写过了 
  38.                 //即通知正在等待的线程有事件发生 
  39.                 autoResetEvent.Set(); 
  40.  
  41.                 //Thread.Sleep(1); 
  42.             } 
  43.  
  44.             //终止线程 
  45.             readerThread.Abort(); 
  46.         } 
  47.  
  48.         staticvoid ReadThreadProc() 
  49.         { 
  50.             while (true
  51.             { 
  52.                 //在数据被写入前,读线程等待(实际上是等待写线程发出数据写完的信号) 
  53.                 autoResetEvent.WaitOne(); 
  54.                 Console.WriteLine("{0} reading : {1}", Thread.CurrentThread.Name, myData); 
  55.             } 
  56.         } 
  57.     } 
  58. }<pre></pre> 
using System;
using System.Collections.Generic;
using System.Text;

using System.Threading;

namespace TestAutoResetEvent
{
    ///
    /// 读写者线程
    /// 主线程写,子线程读,且只有将数据写入后,读线程才能将其读出
    ///
    class Program
    {
        //写线程将数据写入myData
        static int myData = 100;

        //读写次数
        const int readWriteCount = 10;

        //false:初始时没有信号
        static AutoResetEvent autoResetEvent = new AutoResetEvent(false);

        static void Main(string[] args)
        {
            //开启一个读线程(子线程)
            Thread readerThread = new Thread(new ThreadStart(ReadThreadProc));
            readerThread.Name = "ReaderThread";
            readerThread.Start();

            for (int i = 1; i <= readWriteCount; i++)
            {
                Console.WriteLine("MainThread writing : {0}", i);

                //主(写)线程将数据写入
                myData = i;

                //主(写)线程发信号,说明值已写过了
                //即通知正在等待的线程有事件发生
                autoResetEvent.Set();

                //Thread.Sleep(1);
            }

            //终止线程
            readerThread.Abort();
        }

        static void ReadThreadProc()
        {
            while (true)
            {
                //在数据被写入前,读线程等待(实际上是等待写线程发出数据写完的信号)
                autoResetEvent.WaitOne();
                Console.WriteLine("{0} reading : {1}", Thread.CurrentThread.Name, myData);
            }
        }
    }
}

 

运行结果如下:

 

bubuko.com,布布扣

 

有结果可知,不睡眠的情况和睡眠时间为0(即Thread.Sleep(0);)效果产不多,只是不睡眠丢失的数据更多了。

 

5. 对1再修改

将传递给AutoResetEvent的构造函数的参数设置为true,观察运行结果。

 

  1. using System; 
  2. using System.Collections.Generic; 
  3. using System.Text; 
  4.  
  5. using System.Threading; 
  6.  
  7. namespace TestAutoResetEvent 
  8.     /// <summary> 
  9.     /// 读写者线程 
  10.     /// 主线程写,子线程读,且只有将数据写入后,读线程才能将其读出 
  11.     /// </summary> 
  12.     class Program 
  13.     { 
  14.         //写线程将数据写入myData 
  15.         staticint myData = 100; 
  16.  
  17.         //读写次数 
  18.         constint readWriteCount = 10; 
  19.  
  20.         //false:初始时没有信号 
  21.         static AutoResetEvent autoResetEvent = new AutoResetEvent(true); 
  22.  
  23.         staticvoid Main(string[] args) 
  24.         { 
  25.             //开启一个读线程(子线程) 
  26.             Thread readerThread = new Thread(new ThreadStart(ReadThreadProc)); 
  27.             readerThread.Name = "ReaderThread"
  28.             readerThread.Start(); 
  29.  
  30.             for (int i = 1; i <= readWriteCount; i++) 
  31.             { 
  32.                 Console.WriteLine("MainThread writing : {0}", i); 
  33.  
  34.                 //主(写)线程将数据写入 
  35.                 myData = i; 
  36.  
  37.                 //主(写)线程发信号,说明值已写过了 
  38.                 //即通知正在等待的线程有事件发生 
  39.                 autoResetEvent.Set(); 
  40.  
  41.                 Thread.Sleep(0); 
  42.             } 
  43.  
  44.             //终止线程 
  45.             readerThread.Abort(); 
  46.         } 
  47.  
  48.         staticvoid ReadThreadProc() 
  49.         { 
  50.             while (true
  51.             { 
  52.                 //在数据被写入前,读线程等待(实际上是等待写线程发出数据写完的信号) 
  53.                 autoResetEvent.WaitOne(); 
  54.                 Console.WriteLine("{0} reading : {1}", Thread.CurrentThread.Name, myData); 
  55.             } 
  56.         } 
  57.     } 
  58. }<pre></pre> 
using System;
using System.Collections.Generic;
using System.Text;

using System.Threading;

namespace TestAutoResetEvent
{
    ///
    /// 读写者线程
    /// 主线程写,子线程读,且只有将数据写入后,读线程才能将其读出
    ///
    class Program
    {
        //写线程将数据写入myData
        static int myData = 100;

        //读写次数
        const int readWriteCount = 10;

        //false:初始时没有信号
        static AutoResetEvent autoResetEvent = new AutoResetEvent(true);

        static void Main(string[] args)
        {
            //开启一个读线程(子线程)
            Thread readerThread = new Thread(new ThreadStart(ReadThreadProc));
            readerThread.Name = "ReaderThread";
            readerThread.Start();

            for (int i = 1; i <= readWriteCount; i++)
            {
                Console.WriteLine("MainThread writing : {0}", i);

                //主(写)线程将数据写入
                myData = i;

                //主(写)线程发信号,说明值已写过了
                //即通知正在等待的线程有事件发生
                autoResetEvent.Set();

                Thread.Sleep(0);
            }

            //终止线程
            readerThread.Abort();
        }

        static void ReadThreadProc()
        {
            while (true)
            {
                //在数据被写入前,读线程等待(实际上是等待写线程发出数据写完的信号)
                autoResetEvent.WaitOne();
                Console.WriteLine("{0} reading : {1}", Thread.CurrentThread.Name, myData);
            }
        }
    }
}

 

运行结果如下:

 

bubuko.com,布布扣

 

 

若将主线程的睡眠时间改为任意非0值,其运行结果均为下图所示的结果。

 

bubuko.com,布布扣

                         

6. 其他修改

 

将主线程调用AutoResetEvent对象的Set方法删除,分别对AutoResetEvent的构造函数的参数为false和true观察运行结果。

 

为false,运行结果如下图所示。

 

bubuko.com,布布扣

 

 

为true,运行结果如下图所示。

 

bubuko.com,布布扣

 

至此,我想我们应该明白AutoResetEvent构造函数的参数的意义了。 false:无信号,子线程的WaitOne方法不会被自动调用; true:有信号,子线程的WaitOne方法会被自动调用。

C#读写者线程(用AutoResetEvent实现同步),布布扣,bubuko.com

评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!