【问题标题】:Monitor.Pulse(this) does not trigger Monitor.Wait(this);Monitor.Pulse(this) 不会触发 Monitor.Wait(this);
【发布时间】:2013-02-22 15:02:50
【问题描述】:

我试图让 Monitor.Pulse(this) 在我的代码中触发 Monitor.Wait(this)。我认为我的等待语句都在没有脉冲的情况下运行。我有 5 个不同的线程,由 5 个不同的对象运行,每个对象代表一个具有不同优先级的队列。我试图让每个线程在不使用线程优先级属性(即正常、高于正常等)的情况下以特定优先级运行。无论如何,重点是每个线程只运行一次,然后似乎它们被卡在为每个队列运行的线程中的 Monitor.Wait(this) 部分。有谁知道为什么 Monitor.Pulse(this) 不会触发 Monitor.Wait(this) 并继续循环。每个线程应该由 Monitor.Wait(this) 和使用全局变量 GlobalCount 的 while 循环一个接一个地触发。我认为问题必须出现在我的 Beta 方法中,在发生此触发的顶部的第一类(Msg 类)中。或者在我的主要方法中,虽然我不太确定那部分有问题。

会发生什么,它将执行几行,然后开始一个新行,但不会打印任何其他内容。代码仍在运行。我还尝试删除 Monitor.Pulse 和 Monitor.Wait 并且它部分工作,但是每次 delta 对象的 beta 方法运行其线程时,它都会被 alpha 方法替换。有谁知道这是为什么以及如何让 Pulse and Wait 工作?

这是我的代码(忽略一些 cmets):

   // StopJoin.cs
using System;
using System.Threading;
using System.Collections;



public class Msg
{
string message;
int priority;

public Msg(string ms, int pr)
{message = ms;
priority = pr;}


// This method that will be called when the thread is started
public void Beta()
{



while(true){

//Console.WriteLine("asdfasdfs");
Console.WriteLine(message+":"+GlobalClass.globalCount);
lock(this)   // Enter synchronization block
{
while((priority - 1) != GlobalClass.globalCount){
//Console.WriteLine(GlobalClass.globalCount);
try
{
// Waits for the Monitor.Pulse in WriteToCell
//Console.WriteLine("beginning");
//Monitor.Wait(this);
//Console.WriteLine("end");
}
catch (SynchronizationLockException e)
{
Console.WriteLine(e);
}
catch (ThreadInterruptedException e)
{
Console.WriteLine(e);
}
if(GlobalClass.globalCount >= 5)
    GlobalClass.globalCount = 0;
}
Console.WriteLine(message+".Beta is running in its own thread.");

for(int i = 0;i<priority;i++)
{
Console.WriteLine("sending message...");

}

if(GlobalClass.globalCount < 5)
    GlobalClass.globalCount = GlobalClass.globalCount + 1;


//Monitor.Pulse(this);   // Pulse tells Cell.WriteToCell that
//Console.WriteLine(GlobalClass.globalCount);
}
}
}
}






public class Alpha
{
Msg the_message = new Msg("Alpha",1);

public void doWork()
{the_message.Beta();}
};




public class Charlie
{
Msg the_message = new Msg("Charlie",2);
public void doWork()
{the_message.Beta();}
};






public class Delta
{
Msg the_message= new Msg("Alpha",3);
public void doWork()
{the_message.Beta();}
};





public class Echo
{
Msg the_message= new Msg("Echo",4);
public void doWork()
{the_message.Beta();}
};







public class Foxtrot
{
Msg the_message= new Msg("Foxtrot",5);
public void doWork()
{the_message.Beta();}
};




static class GlobalClass
{
private static int global_count = 0;

public static int globalCount
{
get{return global_count;}
set{global_count = value;}
}
}






public class Simple
{
public static int Main()
{

GlobalClass.globalCount = 2;

long s = 0;
long number = 100000000000000000;

Console.WriteLine("Thread Start/Stop/Join Sample");

Alpha oAlpha = new Alpha();
Charlie oCh = new Charlie();
Delta oDe = new Delta();
Echo oEc = new Echo();
Foxtrot oFo = new Foxtrot();

// Create the thread object, passing in the Alpha.Beta method
// via a ThreadStart delegate. This does not start the thread.
Thread oThread = new Thread(new ThreadStart(oAlpha.doWork));
Thread aThread = new Thread(new ThreadStart(oCh.doWork));
Thread bThread = new Thread(new ThreadStart(oDe.doWork));
Thread cThread = new Thread(new ThreadStart(oEc.doWork));
Thread dThread = new Thread(new ThreadStart(oFo.doWork));

// Start the thread
oThread.Start();
aThread.Start();
bThread.Start();
cThread.Start();
dThread.Start();

// Spin for a while waiting for the started thread to become
// alive:
while (!oThread.IsAlive);
while (!aThread.IsAlive);
while (!bThread.IsAlive);
while (!cThread.IsAlive);
while (!dThread.IsAlive);

// Put the Main thread to sleep for 1 millisecond to allow oThread
// to do some work:
Thread.Sleep(1);



// Wait until oThread finishes. Join also has overloads
// that take a millisecond interval or a TimeSpan object.
oThread.Join();
aThread.Join();
bThread.Join();
cThread.Join();
dThread.Join();

Console.WriteLine();
Console.WriteLine("Alpha.Beta has finished");

/*
try 
{
Console.WriteLine("Try to restart the Alpha.Beta thread");
oThread.Start();
}
catch (ThreadStateException) 
{
Console.Write("ThreadStateException trying to restart Alpha.Beta. ");
Console.WriteLine("Expected since aborted threads cannot be restarted.");
}
*/


while(s<number)
s++;

// Request that oThread be stopped
oThread.Abort();
aThread.Abort();
bThread.Abort();
cThread.Abort();
dThread.Abort();


return 0;
}
}

【问题讨论】:

  • 我建议您重新格式化您的代码并尝试删除一些无用的细节 - 您已经在那里发布了很多代码,其中大部分对回答您的问题没有用处。但是,作为对代码的初始注释,您通常不应该使用 lock(this)...

标签: c#


【解决方案1】:

我可以看到您的代码存在许多问题,但有两个主要问题会影响您。我假设您已注释掉的 Monitor 调用不应被注释(否则代码没有意义)。

首先,您在每个线程下创建一个Msg 的新实例。 Beta 方法锁定Msg 的当前实例(在注释的Monitor.Wait(this) 中),因此每个实例本质上都在等待自己——这将是一个无限等待,因为唯一的Monitor.Pulse 在后面同样的方法,永远也达不到。

因为您的一些 Msg 实例将使用更高的 priority 值创建,它们将完全跳过 while 循环并应继续调用 Monitor.Pulse,但不会等待该脉冲.

稍后在您的 Main 方法中,您有以下内容:

    while (!oThread.IsAlive) ;
    while (!aThread.IsAlive) ;
    while (!bThread.IsAlive) ;
    while (!cThread.IsAlive) ;
    while (!dThread.IsAlive) ;

这是有缺陷的。因为不能保证你的线程的执行顺序,所以上面的代码完全有可能死锁。如果您的oThread 没有立即启动,但dThread 已安排并运行到完成,您可以很容易地看到dThread 已完成并在到达上述最后一行之前“死亡”的情况。

总而言之,我不清楚您的代码试图实现什么,但就目前而言,我希望它每次都会死锁。

【讨论】:

  • 我正在尝试让 Monitor.Pulses 触发 Monitor.Waits。确实发生的脉冲不应该触发正在等待的等待吗?
  • 否,因为脉冲只会触发在同一个对象上等待的等待。此外,根据documentation,“只有锁的当前所有者才能使用 Pulse 向等待对象发出信号。”不要用代码来描述你想要做什么,而是试着描述行为——因为你使用的代码可能不匹配。
猜你喜欢
  • 1970-01-01
  • 2014-03-21
  • 2021-12-23
  • 1970-01-01
  • 2013-11-14
  • 1970-01-01
  • 2021-12-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多