ManualResetEvent和AutoResetEvent的区别

发布时间:2024-06-04 18:24:02 来源:君肯网

C#中的AutoResetEvent和ManualResetEvent用于实现线程同步。其基本工作原理是多个线程持有同一个XXXResetEvent,在这个XXXResetEvent未被set前,各线程都在WaitOne()除挂起;在这个XXXResetEvent被set后,所有被挂起的线程中有一个(AutoResetEvent的情况下)或全部(ManualResetEvent的情况下)恢复执行。

AutoResetEvent与ManualResetEvent的差别在于某个线程在WaitOne()被挂起后重新获得执行权时,是否自动reset这个事件(Event),前者是自动reset的,后者不是。所以从这个角度上也可以解释上段提到的“在这个XXXResetEvent被set后,所有被挂起的线程中有一个(AutoResetEvent的情况下)或全部(ManualResetEvent的情况下)恢复执行”——因为前者一旦被某个线程获取后,立即自动reset这个事件(Event),所以其他持有前者的线程之后WaitOne()时又被挂起;而后者被某个获取后,不会自动reset这个事件(Event),所以后续持有后者的线程在WaitOne()时不会被挂起。

namespace AutoResetEvent_Examples {

class MyMainClass {

/*

* 构造方法的参数设置成false后,表示创建一个没有被set的AutoResetEvent

* 这就导致所有持有这个AutoResetEvent的线程都会在WaitOne()处挂起

* 此时如果挂起的线程数比较多,那么你看一下自己的内存使用量……。

* 如果将参数设置成true,表示创建一个被set的AutoResetEvent

* 持有这个AutoResetEvent的线程们会竞争这个Event

* 此时,在其他条件满足的情况下

* 至少会有一个线程得到执行

* 而不是因得不到Event而导致所有线程都得不到执行

*/

static AutoResetEvent myResetEvent = new AutoResetEvent(false)

static int _Count = 0

static void Main() {

Thread myThread = null

for(int i = 0i &lt100i++) {

myThread = new Thread(new ThreadStart(MyThreadProc))

myThread.Name = "Thread" + i

myThread.Start()

}

myResetEvent.Set()

Console.Read()

}

static void MyThreadProc() {

myResetEvent.WaitOne()

_Count++

Console.WriteLine("In thread:{0},label={1}.",Thread.CurrentThread.Name,_Count)

myResetEvent.Set()

}

}

}

namespace ManualResetEvent_Examples {

class MyMainClass {

/*

* 构造方法的参数设置成false后,表示创建一个没有被set的ManualResetEvent

* 这就导致所有持有这个ManualResetEvent的线程都会在WaitOne()处挂起

* 此时如果挂起的线程数比较多,那么你看一下自己的内存使用量……。

* 如果将参数设置成true,表示创建一个被set的ManualResetEvent

* 持有这个ManualResetEvent的线程们在其他条件满足的情况下

* 会同时得到执行(注意,是同时得到执行!所以本例中的_Count的结果一般是不正确的^_^)

* 而不是因得不到Event而导致所有线程都得不到执行

*/

static ManualResetEvent myResetEvent = new ManualResetEvent(false)

static int _Count = 0

static void Main() {

Thread myThread = null

for(int i = 0i &lt1000i++) {

myThread = new Thread(new ThreadStart(MyThreadProc))

myThread.Name = "Thread" + i

myThread.Start()

}

myResetEvent.Set()

Console.Read()

}

static void MyThreadProc() {

myResetEvent.WaitOne()

_Count++

/*

* 在new ManualResetEvent(false)的情况下

* 下面的输出结果可能比较诡异:多个线程都输出label=1000!

* 一种可能的原因是多个线程在各自执行到_Count++后,被挂起

* 随后打印的_Count值就不是本线程中刚刚修改过的_Count值了。

*/

Console.WriteLine("In thread:{0},_Count={1}.",Thread.CurrentThread.Name,_Count)

}

}

}

set是让事件(Event)发生,而reset是让事件(Event)复位或者说忽略已经的事件(Event)。WaitOne是等待事件(Event)的发生,之后继续向下执行,否则一直等待。

在构造AutoResetEvent和ManualResetEvent的时候,它们的构造方法里需要一个参数initState,中文版MSDN(2005和2008)上的解释是“若要将初始状态设置为终止,则为 true;若要将初始状态设置为非终止,则为false。”,我看了一个下午,没弄明白,而看一下英文版后大概就明白了“A value that you set totrueto set the initial state of the specified event to signaled. Set this value tofalseto set the initial state of the event to nonsignaled.”(参见:http://msdn.microsoft.com/en-us/library/ee432364.aspx),大体意思是说这个参数决定是否在构造这个Event的时候就设置它为“发生”状态(signaled),如果是,则设置为true,也就是说持有这个Event的一个或多个线程在一开始就可以执行,而不需要挂起,至少是不会全部挂起(持有AutoResetEvent的一个或多个线程在任意时刻至多有一个线程在执行;持有ManualResetEvent的一个或多个线程会同时执行),否则为false(持有AutoResetEvent和ManualResetEvent的所有线程都将挂起,因为事件(Event)没有被set,即事件没有发生)。

另外稍微提一下,我在做多线程测试的时候,发现在线程数少的情况下,即使多个线程不做任何同步,如果对一个公共变量进行非互斥式修改时,不会至少很难出现不一致的情况,比如开100个线程,这个线程不做任何同步就分别给一个公共变量执行加1操作,那么结果在绝绝绝大部分的情况下是100!所以,我最后就下了狠心,把线程数增加到1000个,这个时候才出现问题,但问题也不是想象得那么严重——结果在991-1000之间!

再有,MSDN上对Monitor的Wait和Pulse两个方法用法的举例会导致死锁,一种死锁的执行顺序是:

1、线程tSecond在SecondThread()中执行到while(Monitor.Wait(m_smplQueue,1000))后,释放m_smplQueue的锁,线程tSecond挂起;

2、线程tFirst在FirstThread()中执行到Monitor.Wait(m_smplQueue)之前耗费的时间超过1000毫秒,此时线程tSecond退出,线程tFirst挂起,并且从此以后不会被恢复!

可以使用如下改动过的代码验证:

public void FirstThread() {

int counter = 0

lock(m_smplQueue) {

Console.WriteLine("11")

while(counter &ltMAX_LOOP_TIME) {

//Wait, if the queue is busy.

Console.WriteLine("12")

Monitor.Wait(m_smplQueue)

Console.WriteLine("13")

//Push one element.

m_smplQueue.Enqueue(counter)

Console.WriteLine("14")

//Release the waiting thread.

Monitor.Pulse(m_smplQueue)

Console.WriteLine("15")

counter++

Console.WriteLine("16")

}

}

}

public void SecondThread() {

lock(m_smplQueue) {

Console.WriteLine("21")

//Release the waiting thread.

Monitor.Pulse(m_smplQueue)

ManualResetEvent和AutoResetEvent的区别

Console.WriteLine("22")

//Wait in the loop, while the queue is busy.

//Exit on the time-out when the first thread stops.

while(Monitor.Wait(m_smplQueue,1000)) {

Console.WriteLine("23")

//Pop the first element.

int counter = (int) m_smplQueue.Dequeue()

Console.WriteLine("24")

//Print the first element.

Console.WriteLine(counter.ToString())

Console.WriteLine("25")

//Release the waiting thread.

Monitor.Pulse(m_smplQueue)

Console.WriteLine("26")

}

Console.WriteLine("27")

}

}

C# AutoResetEvent的使用

使用ManualResetEvent.Reset()方法能将ManualResetEvent设置为nonsignaled,未发出信号状态。此时,所有内部代码包含有“ManualResetEvent.waitOne”这句的线程,都会在运行到“ManualResetEvent.waitOne”这句时,发生阻塞,就是停止不动了。直到ManualResetEvent被ManualResetEvent.Set()方法设置为signaled,即变成发出信号状态。阻塞就会消失,那么所有线程都可以越过“ManualResetEvent.waitOne”这句,继续去执行下面的代码。这个类的作用就是去控制其他线程的暂停与继续执行的。

(之前写反了,没注意,现在看到评论,就改好了,谢谢评论的提醒)

如何判断manualresetevent处于终止状态

C# AutoResetEvent的使用

AutoResetEvent 允许线程通过发信号互相通信。通常,此通信涉及线程需要独占访问的资源。线程通过调用 AutoResetEvent 上的 WaitOne 来等待信号。如果 AutoResetEvent 处于非终止状态,则该线程阻塞,并等待当前控制资源的线程

通过调用 Set 发出资源可用的信号。

调用 Set 向 AutoResetEvent 发信号以释放等待线程。AutoResetEvent 将保持终止状态,直到一个正在等待的.线程被释放,然后自动返回非终止状态。如果没有任何线程在等待,则状态将无限期地保持为终止状态。

可以通过将一个布尔值传递给构造函数来控制 AutoResetEvent 的初始状态,如果初始状态为终止状态,则为 true否则为 false。

通俗的来讲只有等myResetEven.Set()成功运行后,myResetEven.WaitOne()才能够获得运行机会Set是发信号,WaitOne是等待信号,只有发了信号,

等待的才会执行。如果不发的话,WaitOne后面的程序就永远不会执行。下面我们来举一个例子:我去书店买书,当我选中一本书后我会去收费处付钱,

付好钱后再去仓库取书。这个顺序不能颠倒,我作为主线程,收费处和仓库做两个辅助线程,代码如下:

using System

using System.Linq

using System.Activities

using System.Activities.Statements

using System.Threading

namespace CaryAREDemo

{

class Me

{

const int numIterations = 550

static AutoResetEvent myResetEvent = new AutoResetEvent(false)

static AutoResetEvent ChangeEvent = new AutoResetEvent(false)

//static ManualResetEvent myResetEvent = new ManualResetEvent(false)

//static ManualResetEvent ChangeEvent = new ManualResetEvent(false)

static int number//这是关键资源

static void Main()

{

Thread payMoneyThread = new Thread(new ThreadStart(PayMoneyProc))

payMoneyThread.Name = "付钱线程"

Thread getBookThread = new Thread(new ThreadStart(GetBookProc))

getBookThread.Name = "取书线程"

payMoneyThread.Start()

getBookThread.Start()

for (int i = 1i &lt= numIterationsi++)

{

Console.WriteLine("买书线程:数量{0}", i)

number = i

//Signal that a value has been written.

myResetEvent.Set()

ChangeEvent.Set()

Thread.Sleep(0)

}

payMoneyThread.Abort()

getBookThread.Abort()

}

static void PayMoneyProc()

{

while (true)

{

myResetEvent.WaitOne()

//myResetEvent.Reset()

Console.WriteLine("{0}:数量{1}", Thread.CurrentThread.Name, number)

}

}

static void GetBookProc()

{

while (true)

{

ChangeEvent.WaitOne()

// ChangeEvent.Reset()

Console.WriteLine("{0}:数量{1}", Thread.CurrentThread.Name, number)

Console.WriteLine("------------------------------------------")

Thread.Sleep(0)

}

}

}

}

运行结果如下:

AutoResetEvent与ManualResetEvent的区别

他们的用法\声明都很类似,Set方法将信号置为发送状态 Reset方法将信号置为不发送状态WaitOne等待信号的发送。其实,从名字就可以看出一个手动,

一个自动,这个手动和自动实际指的是在Reset方法的处理上,如下面例子:

public AutoResetEvent autoevent=new AutoResetEvent(true)

public ManualResetEvent manualevent=new ManualResetEvent(true)

默认信号都处于发送状态,

autoevent.WaitOne()

manualevent.WaitOne()

如果 某个线程调用上面该方法,则当信号处于发送状态时,该线程会得到信号,得以继续执行。差别就在调用后,autoevent.WaitOne()每次只允许一个线程

进入,当某个线程得到信号(也就是有其他线程调用了autoevent.Set()方法后)后,autoevent会自动又将信号置为不发送状态,则其他调用WaitOne的线程只

有继续等待.也就是说,autoevent一次只唤醒一个线程。而manualevent则可以唤醒多个线程,因为当某个线程调用了set方法后,其他调用waitone的线程

获得信号得以继续执行,而manualevent不会自动将信号置为不发送.也就是说,除非手工调用了manualevent.Reset().方法,则manualevent将一直保持有信号状态,manualevent也就可以同时唤醒多个线程继续执行。如果上面的程序换成ManualResetEvent的话,就需要在waitone后面做下reset。

AutoResetEvent.Set() 这个方法的问题,请专业人士回答

使用ManualResetEvent.set()方法能将ManualResetEvent设置为fasle,非终止状态,此时,所有内部代码包含有“ManualResetEvent.waitOne”这句的线程,都会在运行到“ManualResetEvent.waitOne”这句时,发生阻塞,就是停止不动了。直到ManualResetEvent被ManualResetEvent.reset()方法设置为true,即变成终止状态。阻塞就会消失,那么所有线程都可以越过“ManualResetEvent.waitOne”这句,继续去执行下面的代码。这个类的作用就是去控制其他线程的暂停与继续执行的。

事件是static AutoResetEvent myResetEvent = new AutoResetEvent(false)这一行定义的。

AutoResetEvent 自动回调的事件吧,每当满足某种条件就自动在另个线程执行一段代码,“状态设置为终止状态”就是说当已经满足特定条件的情况下,myResetEvent 这个事件也不自动执行。

以上就是关于ManualResetEvent和AutoResetEvent的区别全部的内容,如果了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

更多相关资讯

C#中的AutoResetEvent和ManualResetEvent用于实现线程同步。其基本工作原理是多个线程持有同一个XXXResetE…
查看详情
C#中的AutoResetEvent和ManualResetEvent用于实现线程同步。其基本工作原理是多个线程持有同一个XXXResetE…
查看详情
C#中的AutoResetEvent和ManualResetEvent用于实现线程同步。其基本工作原理是多个线程持有同一个XXXResetE…
查看详情
相关文章
推荐游戏
风之谷
风之谷
游戏资讯 10.5M
下载
斗罗大陆3
斗罗大陆3
游戏资讯 566.9M
下载
冠军网球
冠军网球
游戏资讯 148.1M
下载
最佳炮手
最佳炮手
游戏资讯 68.1M
下载
如梦下弦月
如梦下弦月
游戏资讯 840.1M
下载
富甲封神传
富甲封神传
游戏资讯 263.0M
下载