AutoResetEvent控制线程用法
注: Suspend,Resume来控制线程已经在.net framework2.0被淘汰了,原因就是挂起之后,但因为异常而没有及时恢复,如果占用资源会导致死锁。
AutoResetEvent概念
- AutoResetEvent对象用来进行线程同步操作,AutoResetEvent类继承waitHandle类。waitOne()方法就继承来自waitHandle类。
- AutoResetEvent对象有终止和非终止两种状态,终止状态是线程继续执行,非终止状态使线程阻塞,可以调用set和reset方法使对象进入终止和非终止状态。-》可以简单理解如果AutoResetEvent对象是终止状态,就像不管别人了,任你撒野去(waitOne()得到的都是撒野信号)
- AutoResetEvent顾名思义,其对象在调用一次set之后会自动调用一次reset,进入非终止状态使调用了等待方法的线程进入阻塞状态。-》可以简单理解如果AutoResetEvent对象是非终止状态,就开始管理起别人来了,此时waitOne()得到的信号都是呆在原地不动信号。
- waitHandle对象的waitone可以使当前线程进入阻塞状态,等待一个信号。直到当前 waitHandle对象收到信号,才会继续执行。
- set可以发送一个信号,允许一个调用waitone而等待线程继续执行。 ManulResetEvent的set方法可以允许多个。但是要手动关闭,即调用reset();
- reset可以使因为调用waitone() 而等待线程都进入阻塞状态。
AutoResetEvent主要方法及实践
- AutoResetEvent(bool initialState):构造函数,用一个指示是否将初始状态设置为终止的布尔值初始化该类的新实例。 false:无信号,子线程的WaitOne方法不会被自动调用 true:有信号,子线程的WaitOne方法会被自动调用
- Reset ():将事件状态设置为非终止状态,导致线程阻止;如果该操作成功,则返回true;否则,返回false。
- Set ():将事件状态设置为终止状态,允许一个或多个等待线程继续;如果该操作成功,则返回true;否则,返回false。
- WaitOne(): 阻止当前线程,直到收到信号。
- WaitOne(TimeSpan, Boolean) :阻止当前线程,直到当前实例收到信号,使用 TimeSpan 度量时间间隔并指定是否在等待之前退出同步域。
有了上面的解释,开始展示代码(经过多次优化)
//若要将初始状态设置为终止,则为 true;若要将初始状态设置为非终止,则为 false
static AutoResetEvent oddResetEvent = new AutoResetEvent(false);
static AutoResetEvent evenResetEvent = new AutoResetEvent(false);
static int i = 0;
static void Main(string[] args)
{
//ThreadStart是个委托
Thread thread1 = new Thread(new ThreadStart(show));
thread1.Name = "偶数线程";
Thread thread2 = new Thread(new ThreadStart(show));
thread2.Name = "奇数线程";
thread1.Start();
Thread.Sleep(2); //保证偶数线程先运行。
thread2.Start();
Console.Read();
}
public static void show()
{
while (i <= 100)
{
int num = i % 2;
if (num == 0)
{
Console.WriteLine("{0}:{1} {2} ", Thread.CurrentThread.Name, i++, "evenResetEvent");
if(i!=1) evenResetEvent.Set();
oddResetEvent.WaitOne(); //当前线程阻塞
}
else
{
Console.WriteLine("{0}:{1} {2} ", Thread.CurrentThread.Name, i++, "oddResetEvent");
//如果此时AutoResetEvent 为非终止状态,则线程会被阻止,并等待当前控制资源的线程通过调用 Set 来通知资源可用。否则不会被阻止
oddResetEvent.Set();
evenResetEvent.WaitOne();
}
}
}
结果如下图所示:

注意点:
不要有一点点点点多余的evenResetEvent.Set(),他会让后续的 evenResetEvent.WaitOne();失效.
第二种方法Semaphore
此外,我们利用信号量也可以实现,信号量是一种内核模式锁,对性能要求比较高,特殊情况下才考虑使用,而且要避免在内核模式和用户模式下频繁相互切换线程。代码如下:
private static readonly int MaxSize = 1;
private static int i = 0;
static Semaphore oddSemaphore = new Semaphore(0, MaxSize);
static Semaphore evenSemaphore = new Semaphore(0, MaxSize);
static void Main(string[] args)
{
System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start();
//ThreadStart是个委托
Thread thread1 = new Thread(new ThreadStart(show));
thread1.Name = "偶数线程";
Thread thread2 = new Thread(new ThreadStart(show));
thread2.Name = "奇数线程";
thread1.Start();
thread2.Start();
thread1.Join();
stopwatch.Stop();
Console.WriteLine(stopwatch.Elapsed.TotalMilliseconds);
Console.Read();
}
private static void show()
{
if(i==1) evenSemaphore.WaitOne();
while (i <= 100)
{
int num = i % 2;
if (num == 0)
{
Console.WriteLine("{0}:{1} {2} ", Thread.CurrentThread.Name, i++, Thread.CurrentThread.ManagedThreadId);
evenSemaphore.Release();
oddSemaphore.WaitOne(); //当前线程阻塞
}
else
{
Console.WriteLine("{0}:{1} {2} ", Thread.CurrentThread.Name, i++, Thread.CurrentThread.ManagedThreadId);
//释放一个偶数信号空位出来;
oddSemaphore.Release();
evenSemaphore.WaitOne(); //当前线程阻塞
//此时已经消耗了一个奇数信号空位
}
}
}
第三种方法,约定每个线程只干自己的事
这种方法利用线程池本身就是队列的方式,即先进先出。测试之后发现性能有下降,但是还是贴出来供参考。
static int threadCount = 2;
static int count = 0;
static object cursorLock = new object();
static void Main(string[] args)
{
System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start();
Task[] arr = new Task[2];
for (int threadIndex = 0; threadIndex < threadCount; threadIndex++)
{
//这两种方法都可以
arr[threadIndex] = Task.Factory.StartNew(PrintNum, threadIndex);
}
Task.WaitAll(arr);
stopwatch.Stop();
Console.WriteLine(stopwatch.Elapsed.TotalMilliseconds);
Console.Read();
}
private static void PrintNum(object num)
{
bool isOk = false;
while (!isOk)
{
lock (cursorLock)
{
int index = count % 2;
if (count>100)
{
isOk = true;
}
else if (index == (int)num)
{
if (index == 0) Console.WriteLine("{0}:{1} {2} ", "偶数线程", Thread.CurrentThread.ManagedThreadId, count++);
else Console.WriteLine("{0}:{1} {2} ", "奇数线程", Thread.CurrentThread.ManagedThreadId, count++);
}
}
}
}
结果如下:

第四种方法 Mutex
private static int i = 0;
static Mutex mutex = new Mutex();
static void Main(string[] args)
{
System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start();
//ThreadStart是个委托
Thread thread1 = new Thread(new ParameterizedThreadStart(show));
thread1.Name = "偶数线程";
Thread thread2 = new Thread(new ParameterizedThreadStart(show));
thread2.Name = "奇数线程";
thread1.Start(0);
thread2.Start(1);
thread2.Join();
stopwatch.Stop();
Console.WriteLine(stopwatch.Elapsed.TotalMilliseconds);
Console.Read();
}
/// <summary>
/// Mutex的释放与锁定 都只能在同一个线程中执行
/// </summary>
private static void show(object index)
{
while (i <= 100)
{
mutex.WaitOne();
int num = i % 2;
if (num == (int)index&&i<=100)
{
Console.WriteLine("{0}:{1} {2} ", Thread.CurrentThread.Name, i++, Thread.CurrentThread.ManagedThreadId);
}
mutex.ReleaseMutex();
}
}
有关概念资料
https://www.cnblogs.com/michaelxu/archive/2008/09/20/1293716.html
AutoResetEvent控制线程用法的更多相关文章
- C# 使用AutoResetEvent进行线程同步
AutoResetEvent 允许线程通过发信号互相通信. 通常,当线程需要独占访问资源时使用该类. 线程通过调用 AutoResetEvent 上的 WaitOne 来等待信号. 如果 AutoRe ...
- MFC多线程各种线程用法 .
http://blog.csdn.net/qq61394323/article/details/9328301 一.问题的提出 编写一个耗时的单线程程序: 新建一个基于对话框的应用程序SingleTh ...
- C# 多线程 线程池(ThreadPool) 2 如何控制线程池?
线程池启动了,但是没有方法去控制线程池,如果子线程出现了问题,难道线程池就死了吗? 我们可以设置线程池的线程数量,进行加入任务,线程池会自动分配并且合理的执行,但是控制不了又有啥意思呢. 线程池里线程 ...
- Condition控制线程通信
Condition控制线程通信 一.前言 java.util.concurrent.locks.Condition 接口描述了可能会与锁有关联的条件变量.这些变量在用法上与使用Object.wait ...
- Java---Condition控制线程通信
java中控制线程通信的方法有:1.传统的方式:利用synchronized关键字来保证同步,结合wait(),notify(),notifyAll()控制线程通信.不灵活. 2.利用Conditio ...
- Java核心知识点学习----使用Condition控制线程通信
一.需求 实现线程间的通信,主线程循环3次后,子线程2循环2次,子线程3循环3次,然后主线程接着循环3次,如此循环3次. 即:A->B->C---A->B->C---A-> ...
- 使用Thread类可以创建和控制线程
1.创建线程 static void Main(string[] args) { /* Thread类 * 创建控制线程 * 其构造函数接受ThreadStart和ParameterizedThrea ...
- [转载]C# 多线程、控制线程数提高循环输出效率
C#多线程及控制线程数量,对for循环输出效率. 虽然输出不规律,但是效率明显提高. 思路: 如果要删除1000条数据,只使用for循环,则一个接着一个输出.所以,把1000条数据分成seed段,每段 ...
- Java中怎么控制线程訪问资源的数量
在API中是这样来描写叙述Semaphore 的 Semaphore 通经常使用于限制能够訪问某些资源(物理或逻辑的)的线程数目. 一个计数信号量.从概念上讲,信号量维护了一个许可集.如有必要,在许可 ...
随机推荐
- WinForm控件之【ListView】
基本介绍 项列表控件,拥有五种不同视图的样式供展示项集合. 常设置属性 Columns:‘详细信息’视图中用来显示的列: Groups:ListView列表中的组,将列表各项分组区域展示: Horiz ...
- python实现DFA模拟程序(附java实现代码)
DFA(确定的有穷自动机) 一个确定的有穷自动机M是一个五元组: M=(K,∑,f,S,Z) K是一个有穷集,它的每个元素称为一个状态. ∑是一个有穷字母表,它的每一个元素称为一个输入符号,所以也陈∑ ...
- [原创]Greenplum数据库集群实践
GreenPlum实践 ============================================== 目录: 一.安装环境准备 二.GP数据库安装 三.集群添加standby节点 四. ...
- 什么是常量?变量? if语句介绍
1.python 的历史 2004 年 Django 的产生 phyton2与 python3 的区别 Python2:源码不统一,有重复的代码功能 Python3:源码统一,没有有重复的代码功能 2 ...
- python基本用法
PYTHONPATH PYTHONPATH是python moudle的搜索路径.即import xxx会从$PYTHONPATH寻找xxx. 中文编码问题 #coding=utf-8 查看导入的包的 ...
- 抓包自定义过滤器需加%XXXX%,如%third_play%
抓包自定义过滤器需加%XXXX%,如%third_play%
- weex起步
weex文档地址: http://weex-project.io/cn/guide/index.html weex的文档过于简单,加上js语法 & android & ios本身也有很 ...
- 【算法•日更•第十九期】动态规划:RMQ问题
▎前言 首先先来说一下RMB是什么,当然是人民币啦. 今天我们要学的这个东西不一般,叫做RMQ问题,那么它和RMB有什么关系呢?待小编细细说来. ▎前置技能:动态规划 不会的同志请戳这里迅速了解动态规 ...
- Git更改提交
提交记录我们的工作历史记录,提交自身是一成不变的.Git提供了几个工具和命令,抓门用来帮助修改完善版本库中的提交. 实际工作中存在很多情况需要我们去修改或返工某个提交或者整个提交序列: 1,可以在某个 ...
- 从7点到9点写的小程序(用了模块导入,python终端颜色显示,用了点局部和全局可变和不可变作用域,模块全是自定义)
未完待续的小程序 要是能做的好看为啥不做的好看 在同目录下生成程序 1.程序文件 run.py from login import login from register import registe ...