如何优雅地终止 BLOCKED 线程?

Art*_*ode 5 c# multithreading

有很多地方可以优雅地终止 C# 线程。然而,它们依赖于循环或循环内执行的 if 条件,这假设该语句将被频繁执行;因此,当stop设置了 bool 标志时,线程会快速退出。

如果我有一个线程的情况不正确怎么办?就我而言,这是一个设置为从服务器接收数据的线程,该线程经常阻塞从输入流读取数据的调用,而尚未提供任何数据,因此它会等待。

这是问题循环中的线程:

    while (true)
        {
            if (EndThread || Commands.EndRcvThread)
            {
                Console.WriteLine("Ending thread.");
                return;
            }

            data = "";
            received = new byte[4096];

            int bytesRead = 0;
            try
            {
                bytesRead = stream.Read(received, 0, 4096);
            }
            catch (Exception e)
            {
                Output.Message(ConsoleColor.DarkRed, "Could not get a response from the server.");
                if (e.GetType() == Type.GetType("System.IO.IOException"))
                {
                    Output.Message(ConsoleColor.DarkRed, "It is likely that the server has shut down.");
                }
            }

            if (bytesRead == 0)
            {
                break;
            }

            int endIndex = received.Length - 1;
            while (endIndex >= 0 && received[endIndex] == 0)
            {
                endIndex--;
            }

            byte[] finalMessage = new byte[endIndex + 1];
            Array.Copy(received, 0, finalMessage, 0, endIndex + 1);

            data = Encoding.ASCII.GetString(finalMessage);

            try
            {
                ProcessMessage(data);
            }
            catch (Exception e)
            {
                Output.Message(ConsoleColor.DarkRed, "Could not process the server's response (" + data + "): " + e.Message);
            }
        }
Run Code Online (Sandbox Code Playgroud)

块顶部的语句if执行通常的正常停止线程设置的操作:检查标志,如果设置了则终止线程。然而,通常可以在下面几行找到该线程,在 处等待stream.Read

鉴于此,有什么方法可以优雅地终止这个线程(即没有Aborting),并清理其资源(有一个客户端需要关闭)?

Ale*_*lex 4

假设您可以使用异步/任务,则干净停止异步和 IO 操作的方法是使用CancelationToken连接到CancelationTokenSource. 下面的代码片段展示了其应用于简化版本的代码时的用法的简化示例。

class MyNetworkThingy 
{
    public async Task ReceiveAndProcessStuffUntilCancelled(Stream stream, CancellationToken token)
    {
        var received = new byte[4096];
        while (!token.IsCancellationRequested)
        {
            try
            {
                var bytesRead = await stream.ReadAsync(received, 0, 4096, token);
                if (bytesRead == 0 || !DoMessageProcessing(received, bytesRead))
                    break; // done.
            }
            catch (OperationCanceledException)
            {
                break; // operation was canceled.
            }
            catch (Exception e)
            {
                // report error & decide if you want to give up or retry.
            }
        }
    }

    private bool DoMessageProcessing(byte[] buffer, int nBytes)
    {
        try
        {
            // Your processing code.
            // You could also make this async in case it does any I/O.
            return true;
        }
        catch (Exception e)
        {
            // report error, and decide what to do.
            // return false if the task should not
            // continue.
            return false;
        }
    }
}

class Program
{
    public static void Main(params string[] args)
    {
        using (var cancelSource = new CancellationTokenSource())
        using (var myStream = /* create the stream */)
        {
            var receive = new MyNetworkThingy().ReceiveAndProcessStuffUntilCancelled(myStream, cancelSource.Token);
            Console.WriteLine("Press <ENTER> to stop");
            Console.ReadLine();
            cancelSource.Cancel();
            receive.Wait();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 任务*可以*使用线程池线程进行调度,但并非必须如此。它们可能在同一线程(ASP.NET 或 WPF 应用程序中的 async/await 常见)、线程池、另一个线程池或它们自己的唯一线程(长时间运行的任务)上运行。 (2认同)