manualresetevent

时间:2024-05-22 18:01:44编辑:coo君

c#线程学习之ManualResetEvent和AutoResetEvent的区别

我理解线程间通讯问题接收a候主线程创建新线程运行函数(比叫WorkRun)新线程(比叫thA)运行主线程接收b需要通知thA使止或改变其运行逻辑
启线程写:
Thread thA = new Thread(new ThreadStart(WorkRun));
thA.Start();
事实两种能场景第种主线程向thA发送止线程指令让函数止执行;另种函数执行某点候停等待主线程给信号决定该执行逻辑
1. 止线程需要接收b候写
if(thA.ThreadState == ThreadState.Running)
{
thA.Abort();
}
2. 需要运行停等待主线程指令使用ManualResetEventManualResetEvent 允许线程通发信号互相通信通通信涉及线程其线程进行前必须完任务

线程始(必须完其线程才能始)调用 Reset ManualResetEvent 置于非终止状态线程视控制 ManualResetEvent调用 ManualResetEvent WaitOne 线程阻止并等待信号控制线程完调用 Set 发等待线程继续进行信号并释放所等待线程

旦终止ManualResetEvent 保持终止状态直手重置即 WaitOne 调用立即返

通布尔值传递给构造函数控制 ManualResetEvent 初始状态初始状态处于终止状态 true;否则 false

ManualResetEvent 同 staticWaitAll WaitAny 起使用

实例(面代码示例阐释何使用等待句柄发送复杂数字计算同阶段完信号计算格式:结 = 第项 + 第二项 + 第三项其每项都要求使用计算基数进行预计算终计算):
using System;
using System.Threading;

class CalculateTest
{
static void Main()
{
Calculate calc = new Calculate();
Console.WriteLine("Result = .",
calc.Result(234).ToString());
Console.WriteLine("Result = .",
calc.Result(55).ToString());
}
}

class Calculate
{
double baseNumber, firstTerm, secondTerm, thirdTerm;
AutoResetEvent[] autoEvents;
ManualResetEvent manualEvent;

// Generate random numbers to simulate the actual calculations.
Random randomGenerator;

public Calculate()
{
autoEvents = new AutoResetEvent[]
{
new AutoResetEvent(false),
new AutoResetEvent(false),
new AutoResetEvent(false)
};

manualEvent = new ManualResetEvent(false);
}

void CalculateBase(object stateInfo)
{
baseNumber = randomGenerator.NextDouble();

// Signal that baseNumber is ready.
manualEvent.Set();
}

// The following CalculateX methods all perform the same
// series of steps as commented in CalculateFirstTerm.

void CalculateFirstTerm(object stateInfo)
{
// Perform a precalculation.
double preCalc = randomGenerator.NextDouble();

// Wait for baseNumber to be calculated.
manualEvent.WaitOne();

// Calculate the first term from preCalc and baseNumber.
firstTerm = preCalc * baseNumber *
randomGenerator.NextDouble();

// Signal that the calculation is finished.
autoEvents[0].Set();
}

void CalculateSecondTerm(object stateInfo)
{
double preCalc = randomGenerator.NextDouble();
manualEvent.WaitOne();
secondTerm = preCalc * baseNumber *
randomGenerator.NextDouble();
autoEvents[1].Set();
}

void CalculateThirdTerm(object stateInfo)
{
double preCalc = randomGenerator.NextDouble();
manualEvent.WaitOne();
thirdTerm = preCalc * baseNumber *
randomGenerator.NextDouble();
autoEvents[2].Set();
}

public double Result(int seed)
{
randomGenerator = new Random(seed);

// Simultaneously calculate the terms.
ThreadPool.QueueUserWorkItem(
new WaitCallback(CalculateBase));
ThreadPool.QueueUserWorkItem(
new WaitCallback(CalculateFirstTerm));
ThreadPool.QueueUserWorkItem(
new WaitCallback(CalculateSecondTerm));
ThreadPool.QueueUserWorkItem(
new WaitCallback(CalculateThirdTerm));

// Wait for all of the terms to be calculated.
WaitHandle.WaitAll(autoEvents);

// Reset the wait handle for the next calculation.
manualEvent.Reset();

return firstTerm + secondTerm + thirdTerm;
}
}


C#里 有关线程 ManualResetEvent的问题

我的理解这是一个线程间通讯的问题,接收到a的时候主线程创建一个新的线程,运行的函数(比如叫WorkRun方法)在新线程(比如叫thA)中运行,当主线程接收到b时需要通知thA使他中止或改变其运行逻辑。
启动线程的写法:
Thread thA = new Thread(new ThreadStart(WorkRun));
thA.Start();
事实上,只有两种可能的场景,第一种是主线程向thA发送中止线程指令,让函数中止执行;另一种是函数在执行到某一个点的时候停下来等待主线程给他一个信号来决定该执行怎样的逻辑。
1. 如果是中止线程的话,只需要在接收到b的时候写
if(thA.ThreadState == ThreadState.Running)
{
thA.Abort();
}
2. 如果需要在运行中停下来等待主线程指令的话,使用ManualResetEvent,ManualResetEvent 允许线程通过发信号互相通信。通常,此通信涉及一个线程在其他线程进行之前必须完成的任务。

当一个线程开始一个活动(此活动必须完成后,其他线程才能开始)时,它调用 Reset 以将 ManualResetEvent 置于非终止状态。此线程可被视为控制 ManualResetEvent。调用 ManualResetEvent 上的 WaitOne 的线程将阻止,并等待信号。当控制线程完成活动时,它调用 Set 以发出等待线程可以继续进行的信号。并释放所有等待线程。

一旦它被终止,ManualResetEvent 将保持终止状态,直到它被手动重置。即对 WaitOne 的调用将立即返回。

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

ManualResetEvent 也可以同 staticWaitAll 和 WaitAny 方法一起使用。

以下为实例(下面的代码示例阐释了如何使用等待句柄来发送复杂数字计算的不同阶段的完成信号。计算的格式为:结果 = 第一项 + 第二项 + 第三项,其中每一项都要求使用计算出的基数进行预计算和最终计算。):
using System;
using System.Threading;

class CalculateTest
{
static void Main()
{
Calculate calc = new Calculate();
Console.WriteLine("Result = .",
calc.Result(234).ToString());
Console.WriteLine("Result = .",
calc.Result(55).ToString());
}
}

class Calculate
{
double baseNumber, firstTerm, secondTerm, thirdTerm;
AutoResetEvent[] autoEvents;
ManualResetEvent manualEvent;

// Generate random numbers to simulate the actual calculations.
Random randomGenerator;

public Calculate()
{
autoEvents = new AutoResetEvent[]
{
new AutoResetEvent(false),
new AutoResetEvent(false),
new AutoResetEvent(false)
};

manualEvent = new ManualResetEvent(false);
}

void CalculateBase(object stateInfo)
{
baseNumber = randomGenerator.NextDouble();

// Signal that baseNumber is ready.
manualEvent.Set();
}

// The following CalculateX methods all perform the same
// series of steps as commented in CalculateFirstTerm.

void CalculateFirstTerm(object stateInfo)
{
// Perform a precalculation.
double preCalc = randomGenerator.NextDouble();

// Wait for baseNumber to be calculated.
manualEvent.WaitOne();

// Calculate the first term from preCalc and baseNumber.
firstTerm = preCalc * baseNumber *
randomGenerator.NextDouble();

// Signal that the calculation is finished.
autoEvents[0].Set();
}

void CalculateSecondTerm(object stateInfo)
{
double preCalc = randomGenerator.NextDouble();
manualEvent.WaitOne();
secondTerm = preCalc * baseNumber *
randomGenerator.NextDouble();
autoEvents[1].Set();
}

void CalculateThirdTerm(object stateInfo)
{
double preCalc = randomGenerator.NextDouble();
manualEvent.WaitOne();
thirdTerm = preCalc * baseNumber *
randomGenerator.NextDouble();
autoEvents[2].Set();
}

public double Result(int seed)
{
randomGenerator = new Random(seed);

// Simultaneously calculate the terms.
ThreadPool.QueueUserWorkItem(
new WaitCallback(CalculateBase));
ThreadPool.QueueUserWorkItem(
new WaitCallback(CalculateFirstTerm));
ThreadPool.QueueUserWorkItem(
new WaitCallback(CalculateSecondTerm));
ThreadPool.QueueUserWorkItem(
new WaitCallback(CalculateThirdTerm));

// Wait for all of the terms to be calculated.
WaitHandle.WaitAll(autoEvents);

// Reset the wait handle for the next calculation.
manualEvent.Reset();

return firstTerm + secondTerm + thirdTerm;
}
}

manualresetevent和autoresetevent的区别

搜索来的,不知道能否帮上你
在讨论这个问题之前,我们先了解这样一种观点,线程之间的通信是通过发信号来进行沟通的。(这不是废话)

先来讨论ManualResetEvent,讨论过程中我会穿插一些AutoResetEvent的内容,来做对比:
ManualResetEvent都可以阻塞一个或多个线程,直到收到一个信号告诉ManualResetEvent不要再阻塞当前的线程。
可以想象ManualResetEvent这个对象内部有一个Boolean类型的属性IsRelease来控制是否要阻塞当前线程。这个属性我们在初始化的时候可以设置它,如ManualResetEvent event=new ManualResetEvent(false);这就表明默认的属性是要阻塞当前线程。
代码举例:
ManualResetEvent _manualResetEvent = new ManualResetEvent(false);
private void BT_Temp_Click(object sender, RoutedEventArgs e)
{
Thread t1 = new Thread(this.Thread1Foo);
t1.Start(); //启动线程1
Thread t2 = new Thread(this.Thread2Foo);
t2.Start(); //启动线程2
Thread.Sleep(3000); //睡眠当前主线程,即调用BT_Temp_Click的线程
_manualResetEvent .Set(); //想象成将IsRelease设为True
}
void Thread1Foo()
{
_manualResetEvent .WaitOne();
//阻塞线程1,直到主线程发信号给线程1,告知_menuResetEvent你的IsRelease属性已经为true,
//这时不再阻塞线程1,程序继续往下跑
MessageBox.Show("t1 end");
}
void Thread2Foo()
{
_manualResetEvent .WaitOne();
//阻塞线程2,直到主线程发信号给线程1,告知_menuResetEvent你的IsRelease属性已经为true,
//这时不再阻塞线程2,程序继续往下跑
MessageBox.Show("t2 end");
}

注意这里ManualResetEvent和AutoResetEvent的一个重要区别:
manual的话肯定会给线程1和线程2都发送一个信号,而auto只会随机给其中一个发送信号。


为什么一个叫manual而一个叫auto呢?我想这是很多人的疑问,现在我们就来看这个问题。
刚才_manualResetEvent .Set();的这句话我想大家都明白了,可以看做将IsRelease的属性设置为true.线程1中
_manualResetEvent.WaitOne();接收到信号后不再阻塞线程1。在此之后的整个过程中IsRelease的值都是true.如果
想将IsRelease的值回复成false,就必须再调用_manualResetEvent.Reset()的方法。

如果是_autoResetEvent.set(),那么_autoResetEvent.WaitOne()后会自动将IsRelease的值自动设置为false.
这就是为什么一个叫auto,一个叫manual.


C#AutoResetEvent和ManualResetEvent的区别

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 = 0;i < 100;i++) {
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 = 0;i < 1000;i++) {
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 < MAX_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);
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#线程学习之ManualResetEvent和AutoResetEvent的区别

先来讨论ManualResetEvent,讨论过程中我会穿插一些AutoResetEvent的内容,来做对比:
ManualResetEvent都可以阻塞一个或多个线程,直到收到一个信号告诉ManualResetEvent不要再阻塞当前的线程。
可以想象ManualResetEvent这个对象内部有一个Boolean类型的属性IsRelease来控制是否要阻塞当前线程。这个属性我们在初始化的时候可以设置它,如ManualResetEvent event=new ManualResetEvent(false);这就表明默认的属性是要阻塞当前线程。
代码举例:
ManualResetEvent _manualResetEvent = new ManualResetEvent(false);
private void BT_Temp_Click(object sender, RoutedEventArgs e)
{
Thread t1 = new Thread(this.Thread1Foo);
t1.Start(); //启动线程1
Thread t2 = new Thread(this.Thread2Foo);
t2.Start(); //启动线程2
Thread.Sleep(3000); //睡眠当前主线程,即调用BT_Temp_Click的线程
_manualResetEvent .Set(); //想象成将IsRelease设为True
}
void Thread1Foo()
{
_manualResetEvent .WaitOne();
//阻塞线程1,直到主线程发信号给线程1,告知_menuResetEvent你的IsRelease属性已经为true,
//这时不再阻塞线程1,程序继续往下跑
MessageBox.Show("t1 end");
}
void Thread2Foo()
{
_manualResetEvent .WaitOne();
//阻塞线程2,直到主线程发信号给线程1,告知_menuResetEvent你的IsRelease属性已经为true,
//这时不再阻塞线程2,程序继续往下跑
MessageBox.Show("t2 end");
}

注意这里ManualResetEvent和AutoResetEvent的一个重要区别:
manual的话肯定会给线程1和线程2都发送一个信号,而auto只会随机给其中一个发送信号。


为什么一个叫manual而一个叫auto呢?我想这是很多人的疑问,现在我们就来看这个问题。
刚才_manualResetEvent .Set();的这句话我想大家都明白了,可以看做将IsRelease的属性设置为true.线程1中
_manualResetEvent.WaitOne();接收到信号后不再阻塞线程1。在此之后的整个过程中IsRelease的值都是true.如果
想将IsRelease的值回复成false,就必须再调用_manualResetEvent.Reset()的方法。

如果是_autoResetEvent.set(),那么_autoResetEvent.WaitOne()后会自动将IsRelease的值自动设置为false.
这就是为什么一个叫auto,一个叫manual.


C#AutoResetEvent和ManualResetEvent的区别

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 = 0;i < 100;i++) {
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 = 0;i < 1000;i++) {
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 < MAX_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);
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");
}
}


ManualResetEvent和AutoResetEvent的区别

先来讨论ManualResetEvent,讨论过程中我会穿插一些AutoResetEvent的内容,来做对比: ManualResetEvent都可以阻塞一个或多个线程,直到收到一个信号告诉ManualResetEvent不要再阻塞当前的线程。 可以想象ManualResetEvent这个对象内部有一个Boolean类型的属性IsRelease来控制是否要阻塞当前线程。这个属性我们在初始化的时候可以设置它,如ManualResetEvent event=new ManualResetEvent(false);这就表明默认的属性是要阻塞当前线程。 代码举例: ManualResetEvent _manualResetEvent = new ManualResetEvent(false); private void BT_Temp_Click(object sender, RoutedEventArgs e) { Thread t1 = new Thread(this.Thread1Foo); t1.Start(); //启动线程1 Thread t2 = new Thread(this.Thread2Foo); t2.Start(); //启动线程2 Thread.Sleep(3000); //睡眠当前主线程,即调用BT_Temp_Click的线程 _manualResetEvent .Set(); //想象成将IsRelease设为True } void Thread1Foo() { _manualResetEvent .WaitOne(); //阻塞线程1,直到主线程发信号给线程1,告知_menuResetEvent你的IsRelease属性已经为true, //这时不再阻塞线程1,程序继续往下跑 MessageBox.Show("t1 end"); } void Thread2Foo() { _manualResetEvent .WaitOne(); //阻塞线程2,直到主线程发信号给线程1,告知_menuResetEvent你的IsRelease属性已经为true, //这时不再阻塞线程2,程序继续往下跑 MessageBox.Show("t2 end"); } 注意这里ManualResetEvent和AutoResetEvent的一个重要区别: manual的话肯定会给线程1和线程2都发送一个信号,而auto只会随机给其中一个发送信号。 为什么一个叫manual而一个叫auto呢?我想这是很多人的疑问,现在我们就来看这个问题。 刚才_manualResetEvent .Set();的这句话我想大家都明白了,可以看做将IsRelease的属性设置为true.线程1中 _manualResetEvent.WaitOne();接收到信号后不再阻塞线程1。在此之后的整个过程中IsRelease的值都是true.如果 想将IsRelease的值回复成false,就必须再调用_manualResetEvent.Reset()的方法。 如果是_autoResetEvent.set(),那么_autoResetEvent.WaitOne()后会自动将IsRelease的值自动设置为false. 这就是为什么一个叫auto,一个叫manual.


ManualResetEvent 终止状态 和非终止状态什么意思

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


c#中sleep()并不能让子线程休息

你需要指定时间的,单位为毫秒
而且注意写的地方,在哪个线程中写就是哪个线程休息
补充:
不太明白你什么意思,你的代码是:
threadstart
=
new
ThreadStart(StartWork);
//
创建一个StartWork方法的委托
newThread
=
new
Thread(threadstart);
//
创建一个使用委托的线程
newThread.Start();
//
线程开始执行
this.Test_thing();
调用了this_thing()函数,因为this_thing是在主进程中执行的,所以挂起的是主进程而不是StartWork
这样才对,你却说他挂起了threadstart进程,这是什么意思?若你想要StartWork挂起,Thread.Sleep(8000)写在StartWork里,在哪个线程中运行这个方法,就是挂起哪个线程


C# 线程……Main()中如果不写Thread.Sleep(一段时间),子线程就不能执行吗?

【有疑问可以HI我,或追问,但请不要关闭问题,谢谢!】

贴上一个你的代码的改版的程序源码你就知道怎么回事了。
1、Main里面Thread.CurrentThread获取的始终是主线程
2、新建的线程,跑完全部就自动结束的
3、myThread.Start();
//Thread.Sleep(1000); //让主线程睡觉zz~~
str = Thread.CurrentThread.Name;
Console.WriteLine("当前线程: " + str);
myThread.Abort();
这里myThread开始后与主线程一起运行,可是主线程却立刻把myThread终止掉了,于是myThread就根本没跑过。你让Thread.Sleep(1000); 这一句有效的话,对主线程阻塞了一定时间,myThread就得以跑起来~~
4、要输出子线程的名字,放在线程的函数Beta里。
5、增加一个“弟弟们”的线程,辅助观察效果。
【本题回答已完全超过了0分题的回答了。用心回答,只为助人】
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace Alpha
{
class Alpha
{

static void Main(string[] args)
{
string str = Thread.CurrentThread.Name;
Console.WriteLine("当前线程: " + str);
Alpha myAlpha = new Alpha();
Thread myThread = new Thread(new ThreadStart(myAlpha.Beta));
myThread.Name = "哥们儿的线程";
myThread.Start();
Thread myThread2 = new Thread(new ThreadStart(myAlpha.Beta));
myThread2.Name = "弟弟们的线程";
myThread2.Start();
//Thread.Sleep(1000); //让主线程睡觉zz~~
str = Thread.CurrentThread.Name;
Console.WriteLine("当前线程: " + str);
//myThread.Abort();
str = Thread.CurrentThread.Name;
Console.WriteLine("当前线程: " + str);
myThread.Join();
str = Thread.CurrentThread.Name;
Console.WriteLine("当前线程: " + str);
Console.Read();
}
private void Beta()
{
for (int i = 0; i < 100; i++)
{
Console.Write("{0} ", i);
}
string str = Thread.CurrentThread.Name;
Console.WriteLine("\n当前线程: " + str);
}
}
}


上一篇:洛克王国小奥可

下一篇:acer4752