Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net Monitor.Wait,Pulse-何时工作线程应该有条件地表现为实际工作线程_.net_Multithreading - Fatal编程技术网

.net Monitor.Wait,Pulse-何时工作线程应该有条件地表现为实际工作线程

.net Monitor.Wait,Pulse-何时工作线程应该有条件地表现为实际工作线程,.net,multithreading,.net,Multithreading,我的具体情况是: -主线程启动工作线程。 -主线程需要阻塞自身,直到工作线程完成(是的,很有趣),或者工作线程本身通知主线程继续 好的,那么我在主线中做了什么: wokerThread.Start(lockObj); lock(lockObj) Monitor.Wait(lockObj); Monitor.Enter(lockObj); workerThread.Start(lockObj); Monitor.Wait(lockObj); 工作线程中的某个位置: if(mainThread

我的具体情况是: -主线程启动工作线程。 -主线程需要阻塞自身,直到工作线程完成(是的,很有趣),或者工作线程本身通知主线程继续

好的,那么我在主线中做了什么:

wokerThread.Start(lockObj);
lock(lockObj)
 Monitor.Wait(lockObj);
Monitor.Enter(lockObj);
workerThread.Start(lockObj);
Monitor.Wait(lockObj);
工作线程中的某个位置:

if(mainThreadShouldGoOn)
 lock(lockObj)
  Monitor.Pulse(lockObj);
lock(lockObj)
 Monitor.Pulse(lockObj);
此外,在辅助线程的末尾:

if(mainThreadShouldGoOn)
 lock(lockObj)
  Monitor.Pulse(lockObj);
lock(lockObj)
 Monitor.Pulse(lockObj);
到目前为止,它工作得很好。但这是一个好的解决方案吗?有更好的吗

编辑:

如果我在主线程中这样做会怎么样:

wokerThread.Start(lockObj);
lock(lockObj)
 Monitor.Wait(lockObj);
Monitor.Enter(lockObj);
workerThread.Start(lockObj);
Monitor.Wait(lockObj);
工人看起来是这样的:

void Worker(object lockObj)
{
 Monitor.Enter(lockObj);
 ...
 ...
 ...
 if(mainThreadShouldGoOn)
 {
  Monitor.Pulse(lockObj);
  Monitor.Exit(lockObj);
 }
 ...
 ...
 ...
 if(!mainThreadShouldGoOn)
 {
  Monitor.Pulse(lockObj);
  Monitor.Exit(lockObj);
 }
}

为什么你启动一个工作线程只是为了在之后马上入睡?你可以简单地在主线程中完成工作

但假设你有理由这么做

我认为您的解决方案在概念上是可以的,但可能存在问题。考虑在主线程启动了工作人员但在获取锁之前发生上下文切换的情况。然后工人将在一个时间段内迅速完成工作。在这种情况下,
Pulse
Wait
之前被调用,因此稍后主线程将永远不会从等待中醒来。下面是一个例子:

class Program
{
    static object theLock = new object();

    static void Main(string[] args)
    {
        Thread worker = new Thread(WorkerMain);
        worker.Start();
        Thread.Sleep(1);
        lock (theLock)
        {
            Monitor.Wait(theLock);
        }
        Console.WriteLine("Main done");
        Console.ReadLine();
    }

    static void WorkerMain()
    {
        lock (theLock)
        {
            Monitor.Pulse(theLock);
        }
    }
}
大多数情况下,此代码将挂起。您可以通过在锁的作用域内移动
worker.Start
来解决此问题

还有一件事需要注意,就是确保调用
Pulse
,即使在特殊情况下也是如此。使用try-finally,它是对的,你会没事的


或考虑将工人的任务分为两部分:一是总是要执行的,另一部分是在<代码> >(MethTuthReuldDoGon){…}/<代码>检查之后执行的。然后,您可以在由main启动的工作线程中执行第一部分,必要时,在另一个工作线程中执行从第一个工作线程启动的第二部分。然后可以使用

Thread.Join()
等待第一个工作进程完成。这将通过牺牲一点性能使同步更简单,更不容易出错。

此代码不正确,如果辅助线程完成得太快,则可能会永久阻塞主线程。这里使用的正确同步对象是ManualResetEvent(或auto,无所谓)。在主线程中调用其Wait()方法,在辅助线程中调用其Set()方法。只要它是一个线程而不是线程池线程,使用Thread.Join()也可以。

嘿,谢谢你的详细回复。根据你的建议,我修改了我的解决方案。请参阅我的原始帖子中的编辑。