如何在线程执行工作时停止服务(不使用thread.Artrt)

本文关键字:thread Artrt 服务 线程 执行 工作 | 更新日期: 2023-09-27 18:24:19

我有一个服务在循环中运行一些不同的任务,直到服务停止。然而,其中一项任务是我调用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);
        }
    }
}

有人能为这个问题提出解决方案吗?

如何在线程执行工作时停止服务(不使用thread.Artrt)

试试这个

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()上阻塞),也没有昂贵的windows内核模式同步对象(AutoResetEvent)。