我做了一些研究并环顾四周,似乎这样做的方法是使用AutoResetEvent。我很快把它放在一起,它似乎工作,似乎是线程安全的。我可以得到一些反馈吗?
class Program
{
private Thread workerThread;
private AutoResetEvent aResetEvent;
private bool _continueProcessing;
private bool active;
private Object locker = new Object();
public Program()
{
workerThread = new Thread(DoSomeProcessing);
workerThread.IsBackground = true;
aResetEvent = new AutoResetEvent(false);
}
public bool ContinueProcessing
{
get
{
lock (locker)
{
return _continueProcessing;
}
}
set
{
if (value)
{
aResetEvent.Set();
}
else
{
aResetEvent.Reset();
}
lock (locker)
{
_continueProcessing = value;
}
}
}
public void DoSomeProcessing()
{
int i = 0;
try
{
while (active)
{
aResetEvent.WaitOne();
// do some work and sleep
lock (locker)
{
if (ContinueProcessing)
{
aResetEvent.Set();
}
}
}
}
catch(ThreadInterruptedException tie)
{
Console.WriteLine("Shutting down.");
}
// any shutdown processing
}
public void StopProcessing()
{
workerThread.Interrupt();
workerThread.Join();
}
public void PauseProcessing()
{
ContinueProcessing = false;
}
public void Continue()
{
ContinueProcessing = true;
}
public void StartProcessing()
{
ContinueProcessing = true;
active = true;
}
}
编辑: 你好,我们又见面了。我已经使用了反馈,我对我的实现更满意。我想添加一个小东西,当我暂停时,我想等待确保线程暂停并且不再工作。那可能吗?也许我应该只用暂停和停止来替换暂停和恢复,然后在停止时执行thred.join()。评论
答案 0 :(得分:1)
调用exit后,ManualResetEvent将被释放,并且在调用时可能会在实例方法上抛出异常。 - >在某些情况下这可能并不理想
class Program {
static void Main(string[] args) {
//NOTE: if worker goes out of scope it will be collected -> ex: promote to field in real use
Worker worker = new Worker();
System.Threading.Thread workerThread = new System.Threading.Thread(new System.Threading.ThreadStart(worker.DoWork));
workerThread.IsBackground = true;
workerThread.Start();
// test
worker.Resume();
System.Threading.Thread.Sleep(2000);
worker.Pause();
System.Threading.Thread.Sleep(2000);
worker.Resume();
System.Threading.Thread.Sleep(2000);
worker.Exit();
System.Threading.Thread.Sleep(5000);
}
}
public class Worker {
private readonly System.Threading.ManualResetEvent _Gate;
private bool _IsActive;
public Worker() {
_Gate = new System.Threading.ManualResetEvent(false);
_IsActive = true;
}
public void DoWork() {
while (IsActive) {
_Gate.WaitOne();
// do work
// can yield the thread
System.Threading.Thread.Sleep(1);
}
// dispose
_Gate.Close();
}
private bool IsActive {
get {
lock (_Gate) {
return _IsActive;
}
}
}
public void Pause() {
_Gate.Reset();
}
public void Resume() {
_Gate.Set();
}
public void Exit() {
lock (_Gate) {
_IsActive = false;
}
}
}
答案 1 :(得分:0)
看起来过于复杂
和
public void StopProcessing()
{
workerThread.Interrupt();
workerThread.Join();
}
如果让线程退出方法,则可以删除
答案 2 :(得分:0)
如果您更改为使用ManualResetEvent,则可以删除_continueProcessing变量。在集合中只需调用事件上的Set或Reset。在getter中,您可以返回aResetEvent.WaitOne(0)。然后,您可以在DoSomeProcessing结束时删除该段代码,如果处理应该是contine,则设置事件。另外,因为ManualResetEvent本身是线程安全的,你可以完全删除锁定。
关于退出DoSomeProcessing方法。可能最好的办法是使用你设置的标志来告诉循环退出,在循环开始时使用锁定来测试标志(是的,你现在必须放回一些锁定)并且你想要什么时候要中止,你设置标志,然后设置事件。
另外,您可以使用另一个事件来表示循环应该退出并更改您的等待以使用WaitHandle.WaitAny()。