监视器.脉冲(此)不会触发监视器.等待(此);

本文关键字:监视器 等待 脉冲 | 更新日期: 2023-09-27 18:00:39

我正在尝试获取Monitor.Pulse(this)来触发Monitor.Wait(this)在我的代码中。我想我的等待语句都在某个时刻运行,没有Pulse。我有5个由5个不同对象运行的不同线程,每个线程代表一个具有不同优先级的队列。我试图让每个线程在不使用线程优先级属性(即正常、非正常等)的情况下以一定的优先级运行。无论如何,重点是每个线程只运行一次,然后它们似乎被卡在了监视器上。在为每个队列运行的线程中等待(这)部分。有人知道为什么监视器。脉冲(这个)没有触发监视器。等待(这个)并继续循环。每个线程都应该由Monitor.Wait(this)和使用全局变量GlobalCount的while循环一个接一个地触发。我认为问题一定发生在我的Beta方法的第一个类(Msg类)中,该类位于触发发生的顶部。或者在我的主要方法中,尽管我不太确定这部分是否有问题。

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

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

   // 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;
}
}

监视器.脉冲(此)不会触发监视器.等待(此);

我可以看到您的代码有很多问题,但主要有两个问题会影响您。我已经假设您注释掉的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在到达上面的最后一行之前完成并"死亡"的情况。

总而言之,我不清楚您的代码试图实现什么,但就目前情况来看,我预计它每次都会死锁。