C# CountdownEvent实现
关于CountdownEvent网上的介绍比较少,因为它是实现和使用都很简单,先看看网上的一些评论吧:
CountDownEvent调用成员函数Wait()将阻塞,直至成员函数Signal() 被调用达特定的次数,这时CountDownEvent称作就绪态,对于处于就绪态的CountDownEvent,调用Wait()函数将不会再阻塞,只有手动调用Reset()函数后,调用Wait()函数将再次阻塞。CountDownEvent可以通过TryAddCount()和AddCount()函数来增加函数Signal() 需被调用的次数,但只有当CountDownEvent处于未就绪态时才会成功。否则根据调用函数的不同,将有可能抛出异常
当有新的需要同步的任务产生时,就调用AddCount增加它的计数,当有任务到达同步点是,就调用Signal函数减小它的计数,当CountdownEvent的计数为零时,就表示所有需要同步的任务已经完成,可以开始下一步任务了。
我们来看看CountdownEvent的实现:
public class CountdownEvent : IDisposable
{
private int m_initialCount; // The original # of signals the latch was instantiated with.
private volatile int m_currentCount; // The # of outstanding signals before the latch transitions to a signaled state.
private ManualResetEventSlim m_event; // An event used to manage blocking and signaling.
private volatile bool m_disposed; // Whether the latch has been disposed.
public CountdownEvent(int initialCount)
{
if (initialCount < )
{
throw new ArgumentOutOfRangeException("initialCount");
} m_initialCount = initialCount;
m_currentCount = initialCount; // Allocate a thin event, which internally defers creation of an actual Win32 event.
m_event = new ManualResetEventSlim(); // If the latch was created with a count of 0, then it's already in the signaled state.
if (initialCount == 0)
{
m_event.Set();
}
}
public int CurrentCount
{
get
{
int observedCount = m_currentCount;
return observedCount < ? : observedCount;
}
}
public bool IsSet
{
get
{
return (m_currentCount <= );
}
} //<returns>true if the signal caused the count to reach zero and the event was set; otherwise, false.
public bool Signal()
{
ThrowIfDisposed();
Contract.Assert(m_event != null); if (m_currentCount <= )
{
throw new InvalidOperationException(Environment.GetResourceString("CountdownEvent_Decrement_BelowZero"));
}
int newCount = Interlocked.Decrement(ref m_currentCount);
if (newCount == 0)
{
m_event.Set();
return true;
}
else if (newCount < )
{
throw new InvalidOperationException(Environment.GetResourceString("CountdownEvent_Decrement_BelowZero"));
}
return false;
} //<returns>true if the signals caused the count to reach zero and the event was set; otherwise, false.
public bool Signal(int signalCount)
{
if (signalCount <= )
{
throw new ArgumentOutOfRangeException("signalCount");
} ThrowIfDisposed();
Contract.Assert(m_event != null); int observedCount;
SpinWait spin = new SpinWait();
while (true)
{
observedCount = m_currentCount;
if (observedCount < signalCount)
{
throw new InvalidOperationException(Environment.GetResourceString("CountdownEvent_Decrement_BelowZero"));
}
if (Interlocked.CompareExchange(ref m_currentCount, observedCount - signalCount, observedCount) == observedCount)
{
break;
}
spin.SpinOnce();
}
if (observedCount == signalCount)
{
m_event.Set();
return true;
}
Contract.Assert(m_currentCount >= , "latch was decremented below zero");
return false;
} public void AddCount(int signalCount)
{
if (!TryAddCount(signalCount))
{
throw new InvalidOperationException(Environment.GetResourceString("CountdownEvent_Increment_AlreadyZero"));
}
}
//<returns> true if the increment succeeded; otherwise, false
public bool TryAddCount(int signalCount)
{
if (signalCount <= )
{
throw new ArgumentOutOfRangeException("signalCount");
} ThrowIfDisposed();
int observedCount;
SpinWait spin = new SpinWait();
while (true)
{
observedCount = m_currentCount;
if (observedCount <= )
{
return false;
}
else if (observedCount > (Int32.MaxValue - signalCount))
{
throw new InvalidOperationException(Environment.GetResourceString("CountdownEvent_Increment_AlreadyMax"));
} if (Interlocked.CompareExchange(ref m_currentCount, observedCount + signalCount, observedCount) == observedCount)
{
break;
}
spin.SpinOnce();
}
return true;
} public void Reset()
{
Reset(m_initialCount);
}
public void Reset(int count)
{
ThrowIfDisposed();
if (count < )
{
throw new ArgumentOutOfRangeException("count");
}
m_currentCount = count;
m_initialCount = count; if (count == )
{
m_event.Set();
}
else
{
m_event.Reset();
}
}
//Blocks the current thread until the is set
public void Wait()
{
Wait(Timeout.Infinite, new CancellationToken());
}
public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken)
{
if (millisecondsTimeout < -)
{
throw new ArgumentOutOfRangeException("millisecondsTimeout");
} ThrowIfDisposed();
cancellationToken.ThrowIfCancellationRequested();
bool returnValue = IsSet;
// If not completed yet, wait on the event.
if (!returnValue)
{
// ** the actual wait
returnValue = m_event.Wait(millisecondsTimeout, cancellationToken);
//the Wait will throw OCE itself if the token is canceled.
}
return returnValue;
}
}
代码非常简单,CountdownEvent内部是实现还是依赖于ManualResetEventSlim实例,int initialCount参数为0是就调用ManualResetEventSlim的set方法,这样Wait的对象就不被阻塞了。IsSet是一个主要属性【return (m_currentCount <= 0)】,Signal()和Signal(int signalCount)方法就是减少m_currentCount的,主要采用原子操作【Interlocked.Decrement(ref m_currentCount)】 和【Interlocked.CompareExchange(ref m_currentCount, observedCount - signalCount, observedCount) == observedCount】,如果减少后m_currentCount==0 就调用set方法,为Wait的线程放行;注意这里面有使用SpinWait的自旋,那么AddCount、TryAddCount和Signal方法相反,主要是增加m_currentCount,实现方式一样,采用原子操作+自旋;Reset还原为初始值,Reset(int count)还原为制定的值,Wait方法主要看是否是IsSet【是则是调用了Set方法的】,则直接返回【当前m_currentCount==0】,否者就调用ManualResetEventSlim的Wai方法。
C# CountdownEvent实现的更多相关文章
- 【C#】【Thread】CountdownEvent任务并行
System.Threading.CountdownEvent 是一个同步基元,它在收到一定次数的信号之后,将会解除对其等待线程的锁定. CountdownEvent 专门用于以下情况:您必须使用 ...
- 重新想象 Windows 8 Store Apps (47) - 多线程之线程同步: Semaphore, CountdownEvent, Barrier, ManualResetEvent, AutoResetEvent
[源码下载] 重新想象 Windows 8 Store Apps (47) - 多线程之线程同步: Semaphore, CountdownEvent, Barrier, ManualResetEve ...
- 并行编程之CountdownEvent的用法
教程:http://blog.gkarch.com/threading/part5.html#the-parallel-class http://www.cnblogs.com/huangxinche ...
- C#并行编程 (Barrier,CountdownEvent,ManualResetEventSlim,SemaphoreSlim,SpinLock,SpinWait )
背景 有时候必须访问变量.实例.方法.属性或者结构体,而这些并没有准备好用于并发访问,或者有时候需要执行部分代码,而这些代码必须单独运行,这是不得不通过将任务分解的方式让它们独立运行. 当任务和线程要 ...
- [C#]『CountdownEvent』任务并行库使用小计
System.Threading.CountdownEvent 是一个同步基元,它在收到一定次数的信号之后,将会解除对其等待线程的锁定. CountdownEvent 专门用于以下情况:您必须使用 ...
- 【Thread】CountdownEvent任务并行[z]
System.Threading.CountdownEvent 是一个同步基元,它在收到一定次数的信号之后,将会解除对其等待线程的锁定. CountdownEvent 专门用于以下情况:您必须使用 ...
- 线程同步-使用CountDownEvent类
CountDownEvent类:信号类,等待直到一定数量的操作完成. 代码Demo: using System; using System.Threading; Main方法下面加入以下代码片段: p ...
- [.net 多线程]CountdownEvent
System.Threading.CountdownEvent 是一个同步基元,它在收到一定次数的信号之后,将会解除对其等待线程的锁定.CountdownEvent在初始化时有一个初始计数量,在每个工 ...
- 《C#多线程编程实战》2.7 CountDownEvent
这个同步线程的类大概是东北的. 很有意思. 会限定你的线程使用的次数,更形象一点的像是你妈,提前准备好你要使用的线程的次数,用不完还不高兴那种的. 使用顺序基本就是 实例化 填充线程的启动次数 使用 ...
随机推荐
- 如何查找物理cpu,cpu核心和逻辑cpu的数量
环境 Red Hat Enterprise Linux 4 Red Hat Enterprise Linux 5 Red Hat Enterprise Linux 6 Red Hat Enterpri ...
- 部署Tomcat及nginx负载均衡
Web应用服务器的选择 (1)IBM的WebSphere及Oracle的WebLogic 性能高,但价格也高 (2)Tomcat 性价比高 Tomcat服务器是一个免费的开放源代码的Web应用 ...
- linux系统虚拟机下安装nginx基础
虽然安装nginx什么的 .以及如何配置等等一系列的资料案例已经很多了 但是作为菜鸟的我还是搞了半天哈 官网上面也有.但是一些细节方面的并没有说明.导致踩了半天坑才搞好 本案例的系统环境 wi ...
- mysql的基础增删改查(一)
修改,操作表:1.建表:create table MyClass(id int(4) not null primary key auto_increment,name char(20) not nul ...
- JavaEE 之 Spring(二)
1.AOP(面向切面编程) a.定义:AOP将分散在系统中的功能块放到一个地方——切面 b.重要术语: ①切面(Aspect):就是你要实现的交叉功能---共通业务处理可以被切入到多个目标对象.并且多 ...
- TF之RNN:实现利用scope.reuse_variables()告诉TF想重复利用RNN的参数的案例—Jason niu
import tensorflow as tf # 22 scope (name_scope/variable_scope) from __future__ import print_function ...
- CodeForces 433C Ryouko's Memory Note (中位数定理)
<题目链接> 题目大意:给你一堆数字,允许你修改所有相同的数字成为别的数字,不过只能修改一次,问你修改后序列相邻数字的距离和最小是多少. 解题分析: 首先,修改不是任意的,否则那样情况太多 ...
- 色彩空间-- RGB\HSV
颜色空间 标签(空格分隔): 计算机视觉 颜色通常用三个独立的属性来描述,三个独立变量综合作用,自然就构成一个空间坐标,这就是颜色空间. RGB和CMY颜色模型都是面向硬件的,而HSV(Hue Sat ...
- Python语言说明
第一章:Python入门一.语言什么是语言:人与人之间的沟通计算机语言:计算机语言,即人和计算机之间的沟通语言. 按照级别分类:机器语言:最底层,最低级的语言,只能识别0/1,电平信号汇编语言:计算机 ...
- springmvc controller动态设置content-type
springmvc RequestMappingHandlerAdapter#invokeHandlerMethod 通过ServletInvocableHandlerMethod#invokeAn ...