【发布时间】:2022-04-21 15:11:31
【问题描述】:
Thread.Suspend() 和 Thread.Resume() 这两个方法自 .NET 2.0 起已过时。为什么?还有什么其他的选择和例子?
【问题讨论】:
标签: c# .net-2.0 thread-safety
Thread.Suspend() 和 Thread.Resume() 这两个方法自 .NET 2.0 起已过时。为什么?还有什么其他的选择和例子?
【问题讨论】:
标签: c# .net-2.0 thread-safety
您需要使用 AutoResetEvent EventWaitHandle。
假设你想做这样的事情(注意:不要这样做!):
private Thread myThread;
private void WorkerThread()
{
myThread = Thread.CurrentThread;
while (true)
{
myThread.Suspend();
//Do work.
}
}
public void StartWorking()
{
myThread.Resume();
}
正如其他人所说,这是一个坏主意。尽管仅在其自己的线程上使用 Suspend 相对安全,但您永远无法确定您是否在线程实际挂起时调用 Resume。所以 Suspend 和 Resume 已经过时了。
相反,您想使用 AutoResetEvent:
private EventWaitHandle wh = new AutoResetEvent();
private void WorkerThread()
{
while(true)
{
wh.WaitOne();
//Do work.
}
}
public void StartWorking()
{
wh.Set();
}
工作线程将在等待句柄上等待,直到另一个线程调用 StartWorking。它的工作原理与暂停/恢复非常相似,因为 AutoResetEvent 只允许“恢复”一个线程。
【讨论】:
Suspend() 和 Resume() 是 Thread 类的方法,你知道,它与线程有关。它们是不好的方法,原因与终止进程比要求停止更糟糕的原因相同。
Thread 类上的任何方法,那么您已经做得很好了。将所有线程管理代码隔离在您的工作线程之外是理想的——不幸的是,这通常无法实现。 Suspend / Resume 特别是(曾经)是一种可能的情况。
所有好的替代方案都是在线程达到它乐于等待的点时工作的。挂起是危险的,因为它可能会在线程持有互斥锁时挂起线程 - 这是死锁的秘诀。
因此,您的线程需要的是一个可以等待的 ManualResetEvent - 在它可以安全地这样做的时候,当它没有持有任何锁时。
【讨论】:
这是有史以来最好的 Thread 教程(用于 C#):http://www.albahari.com/threading/
等待你需要在线程上使用 .Join() 。这将等到胎面完成工作。否则,您将需要使用Wait/Pulse。
【讨论】:
您可以使用 ManualReset 代替 AutoReset:
public class Worker
{
ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
ManualResetEvent _pauseEvent = new ManualResetEvent(true);
Thread _thread;
public Worker() { }
public void Start()
{
_thread = new Thread(DoWork);
_thread.Start();
Console.WriteLine("Thread started running");
}
public void Pause()
{
_pauseEvent.Reset();
Console.WriteLine("Thread paused");
}
public void Resume()
{
_pauseEvent.Set();
Console.WriteLine("Thread resuming ");
}
public void Stop()
{
// Signal the shutdown event
_shutdownEvent.Set();
Console.WriteLine("Thread Stopped ");
// Make sure to resume any paused threads
_pauseEvent.Set();
// Wait for the thread to exit
_thread.Join();
}
public void DoWork()
{
while (true)
{
_pauseEvent.WaitOne(Timeout.Infinite);
if (_shutdownEvent.WaitOne(0))
break;
// Do the work..
Console.WriteLine("Thread is running");
}
}
}
【讨论】:
那个太长了。我需要的是一个快速的示例代码来使用。我从讨论中找到了一个,并由 Mark R. Dawson 在http://bytes.com/groups/net-c/458947-thread-suspend 回答。它解释了过时方法的危险以及如何使用 AutoResetEvent 通知第二个线程继续处理。
【讨论】:
我同意这是一个很棒的教程。 Suspend() 和 Resume() 过时的主要原因是它们是非常危险的方法。在任何时候 Thread t 都可以做任何事情。任何事物。想象一下,您的线程正在读取一个文件并对其进行了锁定。你暂停你的线程。文件保持锁定状态。任何其他资源也是如此。对互斥体的锁定也是如此。
【讨论】:
Thread.Suspend() 和 Thread.Resume() 在 .NET 中已过时或被删除的原因与在 Java 中 Thread.suspend() 和 Thread.resume() 已过时的原因大致相同。比较——
suspend“天生容易死锁”),带有【讨论】:
解决方案: 如果另一个线程本身已挂起,则只有一个线程才能恢复另一个线程。 因此,第一个线程仅在另一个线程暂停自身(即其 ThreadState = Suspended)时才恢复另一个线程,从而使自己准备好恢复。这看起来安全无瑕。
或者,我不了解 .Net 线程?
【讨论】: