C#读写者线程(用AutoResetEvent实现同步)
转载自 http://blog.csdn.net/livelylittlefish/article/details/2735440
本博客(http://blog.csdn.net/livelylittlefish)贴出作者(三二一、小鱼)相关研究、学习内容所做的笔记,欢迎广大朋友指正!
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
- {
- /// <summary>
- /// 读写者线程
- /// 主线程写,子线程读,且只有将数据写入后,读线程才能将其读出
- /// </summary>
- class Program
- {
- //写线程将数据写入myData
- staticint myData = 100;
- //读写次数
- constint readWriteCount = 10;
- //false:初始时没有信号
- static AutoResetEvent autoResetEvent = new AutoResetEvent(false);
- staticvoid 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();
- }
- staticvoid ReadThreadProc()
- {
- while (true)
- {
- //在数据被写入前,读线程等待(实际上是等待写线程发出数据写完的信号)
- autoResetEvent.WaitOne();
- Console.WriteLine("{0} reading : {1}", Thread.CurrentThread.Name, myData);
- }
- }
- }
- }<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);
}
}
}
}
运行结果如下:
由运行结果可以看出,写线程写入的数据有丢失,主要原因是写线程没有给读线程留足够的时间去进行读操作。
3. 对1进行修改
将主线程睡眠时间改为非0值,观察运行结果。
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Threading;
- namespace TestAutoResetEvent
- {
- /// <summary>
- /// 读写者线程
- /// 主线程写,子线程读,且只有将数据写入后,读线程才能将其读出
- /// </summary>
- class Program
- {
- //写线程将数据写入myData
- staticint myData = 100;
- //读写次数
- constint readWriteCount = 10;
- //false:初始时没有信号
- static AutoResetEvent autoResetEvent = new AutoResetEvent(false);
- staticvoid 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();
- }
- staticvoid ReadThreadProc()
- {
- while (true)
- {
- //在数据被写入前,读线程等待(实际上是等待写线程发出数据写完的信号)
- autoResetEvent.WaitOne();
- Console.WriteLine("{0} reading : {1}", Thread.CurrentThread.Name, myData);
- }
- }
- }
- }
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
- {
- /// <summary>
- /// 读写者线程
- /// 主线程写,子线程读,且只有将数据写入后,读线程才能将其读出
- /// </summary>
- class Program
- {
- //写线程将数据写入myData
- staticint myData = 100;
- //读写次数
- constint readWriteCount = 10;
- //false:初始时没有信号
- static AutoResetEvent autoResetEvent = new AutoResetEvent(false);
- staticvoid 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();
- }
- staticvoid ReadThreadProc()
- {
- while (true)
- {
- //在数据被写入前,读线程等待(实际上是等待写线程发出数据写完的信号)
- autoResetEvent.WaitOne();
- Console.WriteLine("{0} reading : {1}", Thread.CurrentThread.Name, myData);
- }
- }
- }
- }<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);
}
}
}
}
运行结果如下:
有结果可知,不睡眠的情况和睡眠时间为0(即Thread.Sleep(0);)效果产不多,只是不睡眠丢失的数据更多了。
5. 对1再修改
将传递给AutoResetEvent的构造函数的参数设置为true,观察运行结果。
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Threading;
- namespace TestAutoResetEvent
- {
- /// <summary>
- /// 读写者线程
- /// 主线程写,子线程读,且只有将数据写入后,读线程才能将其读出
- /// </summary>
- class Program
- {
- //写线程将数据写入myData
- staticint myData = 100;
- //读写次数
- constint readWriteCount = 10;
- //false:初始时没有信号
- static AutoResetEvent autoResetEvent = new AutoResetEvent(true);
- staticvoid 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();
- }
- staticvoid ReadThreadProc()
- {
- while (true)
- {
- //在数据被写入前,读线程等待(实际上是等待写线程发出数据写完的信号)
- autoResetEvent.WaitOne();
- Console.WriteLine("{0} reading : {1}", Thread.CurrentThread.Name, myData);
- }
- }
- }
- }<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);
}
}
}
}
运行结果如下:
若将主线程的睡眠时间改为任意非0值,其运行结果均为下图所示的结果。
6. 其他修改
将主线程调用AutoResetEvent对象的Set方法删除,分别对AutoResetEvent的构造函数的参数为false和true观察运行结果。
为false,运行结果如下图所示。
为true,运行结果如下图所示。
至此,我想我们应该明白AutoResetEvent构造函数的参数的意义了。 false:无信号,子线程的WaitOne方法不会被自动调用; true:有信号,子线程的WaitOne方法会被自动调用。
C#读写者线程(用AutoResetEvent实现同步)的更多相关文章
- C#读写者线程(用AutoResetEvent实现同步)(转载)
C#读写者线程(用AutoResetEvent实现同步) 1. AutoResetEvent简介 通知正在等待的线程已发生事件.无法继承此类. 常用方法简介: AutoResetEvent(bool ...
- Redis总结(五)缓存雪崩和缓存穿透等问题 Web API系列(三)统一异常处理 C#总结(一)AutoResetEvent的使用介绍(用AutoResetEvent实现同步) C#总结(二)事件Event 介绍总结 C#总结(三)DataGridView增加全选列 Web API系列(二)接口安全和参数校验 RabbitMQ学习系列(六): RabbitMQ 高可用集群
Redis总结(五)缓存雪崩和缓存穿透等问题 前面讲过一些redis 缓存的使用和数据持久化.感兴趣的朋友可以看看之前的文章,http://www.cnblogs.com/zhangweizhon ...
- 线程安全、数据同步之 synchronized 与 Lock
本文Demo下载传送门 写在前面 本篇文章讲的东西都是Android开源网络框架NoHttp的核心点,当然线程.多线程.数据安全这是Java中就有的,为了运行快我们用一个Java项目来讲解. 为什么要 ...
- java 线程之对象的同步和异步
一.多线程环境下的同步与异步 同步:A线程要请求某个资源,但是此资源正在被B线程使用中,因为同步机制存在,A线程请求不到,怎么办,A线程只能等待下去. package com.jalja.org.th ...
- JAVA多线程提高二:传统线程的互斥与同步&传统线程通信机制
本文主要是回顾线程之间互斥和同步,以及线程之间通信,在最开始没有juc并发包情况下,如何实现的,也就是我们传统的方式如何来实现的,回顾知识是为了后面的提高作准备. 一.线程的互斥 为什么会有线程的互斥 ...
- GIL 线程池 进程池 同步 异步
1.GIL(理论 重点)2.线程池 进程池3.同步 异步 GIL 是一个全局解释器锁,是一个互斥锁 为了防止竞争解释器资源而产生的 为何需要gil:因为一个python.exe进程中只有一份解释器,如 ...
- 5.4.1 sequenceFile读写文件、记录边界、同步点、压缩排序、格式
5.4.1 sequenceFile读写文件.记录边界.同步点.压缩排序.格式 HDFS和MapReduce是针对大文件优化的存储文本记录,不适合二进制类型的数据.SequenceFile作 ...
- Java并发——线程间通信与同步技术
传统的线程间通信与同步技术为Object上的wait().notify().notifyAll()等方法,Java在显示锁上增加了Condition对象,该对象也可以实现线程间通信与同步.本文会介绍有 ...
- java 线程基本概念 可见性 同步
开发高性能并发应用不是一件容易的事情.这类应用的例子包括高性能Web服务器.游戏服务器和搜索引擎爬虫等.这样的应用可能需要同时处理成千上万个请求.对于这样的应用,一般采用多线程或事件驱动的架构.对于J ...
随机推荐
- android SharedPreferences
除了SQLite数据库外,SharedPreferences也是一种轻型的数据存储方式,它的本质是基于XML文件存储key-value键值 对数据,通常用来存储一些简单的配置信息.其存储位置在/dat ...
- Yii表单验证
我之前在朋友的公司拿到他们oa的代码,发现是用Yii写的,oa系统比较简单,但是程序员对Yii的运用比较好,我拿来学习一下.如果有需要,我可以私下分享这个程序,因为是人家的功劳,不在网上公布代码了,只 ...
- Android 应用启动速度优化
现在很多的应用一开始点击的时候总会出现黑屏或者白屏,甚至前段时间微信也有同样的问题.其实白屏或者黑屏还是一些其他的东西,都是因为Android 主题的问题,只要自己自定义一个启动主题,问题完美解决. ...
- 【转】Win 7 下源码运行OpenERP7.0
原文地址:Win 7 下源码运行OpenERP7.0 安装Python2.7 下载地址:http://www.python.org/getit/注:OpenERP7.0支持的Python版本最高为2. ...
- Selenium IDE- 不同的浏览器
Selenium IDE- 不同的浏览器 Selenium IDE脚本只能对火狐的工具Firefox插件运行测试.使用Selenium-IDE开发的测试可以对其他浏览器所保存为Selenium网络驱动 ...
- python中类的总结
1. 类中的方法 在类里主要有三种方法: a.普通方法:在普通方法定义的时候,需要一个对象的实例参数,从而在类中定义普通方法的时候,都必须传送一个参数self,那么这个参数也就是object b.类方 ...
- 【LeetCode】107 - Binary Tree Level Order Traversal II
Given a binary tree, return the bottom-up level order traversal of its nodes' values. (ie, from left ...
- Python 时间整理
在平常的代码中,我们常常需要与时间打交道.在Python中,与时间处理有关的模块就包括:time,datetime以及calendar.这篇文章,主要讲解time模块. 在开始之前,首先要说明这几点: ...
- STL源码剖析读书笔记--第四章--序列式容器
1.什么是序列式容器?什么是关联式容器? 书上给出的解释是,序列式容器中的元素是可序的(可理解为可以按序索引,不管这个索引是像数组一样的随机索引,还是像链表一样的顺序索引),但是元素值在索引顺序的方向 ...
- ERROR (ClientException) nova image-list
nova image-listERROR (ClientException): The server has either erred or is incapable of performi9e-6c ...