如何在线程正在工作时停止服务(不使用Thread.Abort)

我有一个服务在循环中运行一些不同的任务,直到服务停止。 但是,我调用Web服务和此调用的其中一项任务可能需要几分钟才能完成。 我希望能够立即停止服务,“取消”Web服务调用而不调用Thread.Abort因为这会导致一些奇怪的行为,即使线程正在做的唯一事情是调用此Web服务方法。

如何取消或中断同步方法调用(如果可能的话)? 或者我应该尝试不同的方法?

我已经尝试使用AutoResetEvent ,然后调用Thread.Abort ,它在下面的代码示例中运行正常,但是当在实际服务中实现此解决方案时,我得到一些意外的行为,可能是因为外部库中发生了什么我是使用。

AutoResetEventThread.Abort

 class Program { static void Main(string[] args) { MainProgram p = new MainProgram(); p.Start(); var key = Console.ReadKey(); if (key.Key == ConsoleKey.Q) p.Stop(); } } class MainProgram { private Thread workerThread; private Thread webServiceCallerThread; private volatile bool doWork; public void Start() { workerThread = new Thread(() => DoWork()); doWork = true; workerThread.Start(); } public void Stop() { doWork = false; webServiceCallerThread.Abort(); } private void DoWork() { try { while (doWork) { AutoResetEvent are = new AutoResetEvent(false); WebServiceCaller caller = new WebServiceCaller(are); webServiceCallerThread = new Thread(() => caller.TimeConsumingMethod()); webServiceCallerThread.Start(); // Wait for the WebServiceCaller.TimeConsumingMethod to finish WaitHandle.WaitAll(new[] { are }); // If doWork has been signalled to stop if (!doWork) break; // All good - continue Console.WriteLine(caller.Result); } } catch (Exception e) { Console.Write(e); } } } class WebServiceCaller { private AutoResetEvent ev; private int result; public int Result { get { return result; } } public WebServiceCaller(AutoResetEvent ev) { this.ev = ev; } public void TimeConsumingMethod() { try { // Simulates a method running for 1 minute Thread.Sleep(60000); result = 1; ev.Set(); } catch (ThreadAbortException e) { ev.Set(); result = -1; Console.WriteLine(e); } } } 

有人可以建议解决这个问题吗?

解决方案非常简单:除非您想要阻止几分钟,否则不要拨打几分钟的电话。 如果在没有阻塞的情况下无法做任何特定的事情,可能持续几分钟,就会大声抱怨编写强制要求的代码(或者如果可能的话自己修复)。

一旦你打完电话,就太晚了。 你承诺了。 如果您调用的函数没有提供中止它的安全方法,那么就没有安全的方法了。

试试这个

 public void Start() { workerThread = new Thread(() => DoWork()); doWork = true; workerThread.IsBackground = true; workerThread.Start(); } 

线程是后台线程或前台线程。 后台线程与前台线程相同,除了后台线程不会阻止进程终止。 一旦属于进程的所有前台线程终止,公共语言运行库就结束该进程。 任何剩余的后台线程都会停止并且不会完成。

有关更多详细信息,请参阅http://msdn.microsoft.com/en-us/library/system.threading.thread.isbackground.aspx

所有你想做的就是一次做一个异步Web服务调用,并在每个响应进行另一个调用,你可以省去工作线程,只需进行异步调用,注册回调并从回调中进行另一个异步调用:

 class Program { private static WebServiceCaller.TCMDelegate _wscDelegate; private static readonly WebServiceCaller _wsCaller = new WebServiceCaller(); static void Main(string[] args) { _wscDelegate = _wsCaller.TimeConsumingMethod; MakeWSCallAsync(); Console.WriteLine("Enter Q to quit"); while (Console.ReadLine().ToUpper().Trim()!="Q"){} } public static void MakeWSCallAsync() { _wscDelegate.BeginInvoke(OnWSCallComplete, null); } public static void OnWSCallComplete(IAsyncResult ar) { Console.WriteLine("Result {0}", _wscDelegate.EndInvoke(ar)); MakeWSCallAsync(); } } class WebServiceCaller { public delegate int TCMDelegate(); public int TimeConsumingMethod() { try { // Simulates a method running for 1 minute Thread.Sleep(1000); return 1; } catch (ThreadAbortException e) { return -1; } } } 

没有阻塞(好吧,控制台线程在ReadLine()上阻塞)并且没有窗口核心模式同步对象(AutoResetEvent),这是昂贵的 。