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

1. AutoResetEvent简介

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

常用方法简介:

AutoResetEvent(bool initialState):构造函数,用一个指示是否将初始状态设置为终止的布尔值初始化该类的新实例。
    false:无信号,子线程的WaitOne方法不会被自动调用
    true:有信号,子线程的WaitOne方法会被自动调用

public bool Reset ():将事件状态设置为非终止状态,导致线程阻止;如果该操作成功,则返回true;否则,返回false。 
public bool Set ():将事件状态设置为终止状态,允许一个或多个等待线程继续;如果该操作成功,则返回true;否则,返回false。
    对于具有 EventResetMode.AutoReset(包括 AutoResetEvent)的 EventWaitHandle,Set 方法释放单个线程。如果没有等待线程,等待句柄将一直保持终止状态,直到某个线程尝试等待它,或者直到它的 Reset 方法被调用。

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

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

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

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

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);
            }
        }
    }
}运行结果如下:

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

3. 对1进行修改

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

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);
            }
        }
    }
}运行结果如下:

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

4. 对1再进行修改

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

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);
            }
        }
    }
}

运行结果如下:

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

5. 对1再修改

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

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);
            }
        }
    }
}

运行结果如下:

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

6. 其他修改

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

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

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

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

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/livelylittlefish/archive/2008/07/30/2735440.aspx

转载于:https://www.cnblogs.com/rwzhou/p/4683458.html

C#读写者线程(用AutoResetEvent实现同步)(转载)相关推荐

  1. C# 线程、任务和同步

    1,线程概述 线程是程序汇中独立的指令流.线程有一个优先级,实际上正在处理的程序的位置计数器,一个存储其局部变量的栈.每个线程都有自己的栈.但应用程序的内存和堆由一个进程的所有线程共享. 进程包含资源 ...

  2. Linux 线程的创建与同步

    Linux 线程的创建与同步 1.线程的定义 2.线程的创建和使用 3.理解线程的并发运行 3.线程同步 3.线程的实现 1.线程的定义 线程:进程内部的一条执行路径.是资源调度和执行的基本单位. 进 ...

  3. Java并发——线程间通信与同步技术

    传统的线程间通信与同步技术为Object上的wait().notify().notifyAll()等方法,Java在显示锁上增加了Condition对象,该对象也可以实现线程间通信与同步.本文会介绍有 ...

  4. java 线程之对象的同步和异步

    一.多线程环境下的同步与异步 同步:A线程要请求某个资源,但是此资源正在被B线程使用中,因为同步机制存在,A线程请求不到,怎么办,A线程只能等待下去. package com.jalja.org.th ...

  5. BCB线程的互斥与同步

    线程的互斥与同步     互斥控制是为了避免一个线程在使用某一个对象或全局变量与其他线程发生冲突.实现线程互斥的方法有: (1)   访问代码委托给VCL主线程执行.在线程中若要调用可视化的方法或访问 ...

  6. 036-2018-1028 线程 效率对比 数据共享 同步锁死锁递归锁 守护线程 信号量

    笔记 昨日内容回顾: 队列:Queue 管道 : Pipe ,recv消息的时候 OSError,EOFError,数据不安全的 Manager : 共享数据 , 数据不安全 , 加锁 进程池 : P ...

  7. 如何实现线程间的通讯(转载)

    原文出处: wingjay 正常情况下,每个子线程完成各自的任务就可以结束了.不过有的时候,我们希望多个线程协同工作来完成某个任务,这时就涉及到了线程间通信了. 本文涉及到的知识点:thread.jo ...

  8. Android SQLite多线程读写和线程同步源码分析

    没啥诀窍,只需保证几个线程都是用的一个SQLiteDataBase对象就行了. 如果我们非要在不同线程中用两个或更多的SQLiteDataBase对象呢,当然这些SQLiteDataBase对象所操作 ...

  9. Linux C编程--线程操作2--线程同步详解

    linux线程同步之互斥 在windows中,为了让多个线程达到同步的目的,在对于全局变量等大家都要用的资源的使用上,通常得保证同时只能由一个线程在用,一个线程没有宣布对它的释放之前,不能够给其他线程 ...

  10. 关于操作系统中进程、线程、死锁、同步、进程间通信(IPC)的超详细详解整理

    ​​​​​​​作者主页:https://www.zhihu.com/people/san-hao-bai-du-ren-79 一.什么是进程?什么是线程? 1.1 进程定义 1.2 线程定义 1.3 ...

最新文章

  1. 深度学习与传统图像识别
  2. linux 下修改文件描述符限制
  3. boost库之tcp实例(同步方式)
  4. 开源PaaS工具CloudFoundry落地阿里云
  5. 【STM32】GPIO相关函数和类型
  6. C# 导出 Excel 数字列出现‘0’的解决办法
  7. mysql+表中公共信息,計算mysql中兩個表之間的公共行數
  8. python归并排序 分词_python实现归并排序,归并排序的详细分析
  9. php 上传100m文件,PHP向MySQL中insert100M以上的文件
  10. 关于野指针及指针所指内存被回收后的一些误区
  11. SM6S系列TVS二级管 可通过ISO 7637-2 5a/5b测试
  12. 华为热设计工程师待遇_【华为热设计工程师面试】华为热设计工程师的笔试经历-看准网...
  13. 美国TOP100大学优势专业位置分布!长篇吐血整理!
  14. 2021年高处安装、维护、拆除新版试题及高处安装、维护、拆除考试试卷
  15. 分享几个appstore之外的iOS软件下载网址
  16. WEB、WEB标准、W3C的理解
  17. 在ThinkPad W500 A98上升级Windows 7以及安装硬件驱动和相关程序
  18. 网易2018校招内推笔试-彩色砖块
  19. 小鸡手柄或其他手柄导致的电脑无法熄屏休眠问题
  20. PHP网约车H5打车系统源码 分为乘客端和司机端

热门文章

  1. Linux命令-用户和组管理
  2. 警告: Can't find the request for http://localhost:8080/ibatisSpringDemo/ws/testWS's Observer
  3. stella forum 知识库---一些错误的修补
  4. React-Native 使用自定义IconFont
  5. Kafka 居然还会丢消息?
  6. 自己动手实现一个简单的 IOC,牛皮!!
  7. 掌握了这30道MySQL基础面试题,我成了面霸
  8. 自从阿里拿下 Flink 以后, 你还不懂 Flink 就 out 了
  9. 小型电商Web架构!小而美!值得学习!
  10. Nginx 优秀的核心架构设计揭秘,让你搞懂高并发之道