C# 什么';告诉正在执行循环的线程跳出循环并执行其他操作的正确方法是什么?

C# 什么';告诉正在执行循环的线程跳出循环并执行其他操作的正确方法是什么?,c#,.net,multithreading,thread-abort,event-wait-handle,C#,.net,Multithreading,Thread Abort,Event Wait Handle,以下代码的缺点是,在主线程重置waithandle后,工作线程既不会立即终止,也不会执行最终操作。相反,它将继续做它正在做的事情,直到它到达循环的下一个迭代,此时它将被无限期地阻塞 static void Main() { ManualResetEvent m = new ManualResetEvent(true); // or bool b = true Thread thread = new Thread(new ThreadStart(delegate() { while(

以下代码的缺点是,在主线程重置waithandle后,工作线程既不会立即终止,也不会执行最终操作。相反,它将继续做它正在做的事情,直到它到达循环的下一个迭代,此时它将被无限期地阻塞

static void Main()
{
 ManualResetEvent m = new ManualResetEvent(true); // or bool b = true
 Thread thread = new Thread(new ThreadStart(delegate()
 {
    while(m.WaitOne()) //or while(b)
    {
        //do something
    }
    //perform final operation and exit
 }));

 thread.Start();

 //do something

 m.Reset(); //or b = false

 //do something else
 }
下面的代码的缺点是它使用Abort()方法(有人说应该不惜一切代价避免它),但它完全实现了我想要的:在主线程告诉工作线程脱离循环时,强制它脱离循环,执行最后一个操作,然后退出

static void Main()
{
 Thread thread = new Thread(new ThreadStart(delegate()
 {
    try
    {
        while(true)
        {
            //do something
        }
    }
    catch(ThreadAbortException e)
    {
           //perform final operation and exit
    }
 }));

 thread.Start();

 //do something

 thread.Abort();    

 //do something else
 }
既然这两种解决方案都不理想,那么实现我想要的功能的正确方法是什么


(我更喜欢不涉及.net 4.5任务的解决方案)

如果无法使用.net 4.5(如我在评论中所述),则可以使用布尔值取消循环。在这里,我修改了您的第二个选项:

static void Main()
{
    volatile bool keepGoing = true;

    Thread thread = new Thread(new ThreadStart(delegate()
    {
        while(keepGoing)
        {
            //do something
        }

        //logic to perform when the thread is cancelled
    }));

    thread.Start();

    //do something

    keepGoing = false; 

    //do something else
 }
将布尔值标记为volatile将确保在检查它时始终具有正确的值。这种方法还可以确保在循环中执行的任何操作都已完成,并且不会处于“脏”状态


您可以使用
后台工作人员

static void Main()
{
    BackgroundWorker worker = new BackgroundWorker();
    worker.DoWork += worker_DoWork;
    worker.RunWorkerAsync();

    // do something 

    worker.CancelAsync();

    // do something else
}

void worker_DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorker worker = sender as BackgroundWorker;
    while(!worker.CancellationPending)
    {
        // do something
    }
    // perform final action
}

(代码未经测试)

如果您可以使用.NET 4.5,请查看Task(它提供了一种很好的方法来完成您试图完成的任务)。此解决方案和使用waithandle的解决方案的问题在于,如果在工作人员执行某项操作时发送信号,则在到达循环的下一次迭代之前,它不会停止执行该操作。我希望工作线程在主线程通知它退出循环时立即退出循环。啊,好的。。。那么背景工作者可能是更好的选择。如果您可以使用任务和取消令牌,它们就很好。此解决方案和使用waithandle的解决方案的问题在于,如果在工作人员执行某项操作时发送信号,则在到达循环的下一次迭代之前,它不会停止执行。我希望工作线程在主线程通知它退出循环时立即退出该循环。@JohnSmith您可以检查该操作是否在循环中多次取消,以便更细粒度地控制何时退出循环。为什么它需要立即退出?@JohnSmith“我希望工作线程在主线程告诉它退出循环的那一刻就退出循环”-没有这样的事情。过去从来没有,将来也永远不会。。不管.NET版本是什么。一种或另一种方式(令牌或简单bool变量)-您的线程负责检查它是否可以继续或是退出的时间。。。。。。