首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >CancellationTokenSource是否正确关闭?

CancellationTokenSource是否正确关闭?
EN

Stack Overflow用户
提问于 2016-05-01 21:51:19
回答 1查看 314关注 0票数 0

这里是切入点:

代码语言:javascript
复制
public class Program
{
    private static readonly CancellationTokenSource TokenSource = new CancellationTokenSource();

    public static void Main(string[] args)
    {
        // start the app
        new Bootstrap()
            .RunAsync(TokenSource.Token)
            .Wait();

        Console.CancelKeyPress += (sender, eventArgs) =>
        {
            TokenSource.CancelAfter(500);
        };
    }
}

下面是引导:

代码语言:javascript
复制
public class Bootstrap : IBootstrap
{
    private readonly IServer server;

    private readonly ILogger logger;

    public Bootstrap(
        IServer server,
        ILogger logger)
    {
        this.server = server;
        this.logger = logger;
    }

    public async Task RunAsync(CancellationToken token)
    {
        this.logger.Info("Application Starting...");

        await this.server.StartAsync(token);
    }
}

以下是服务器:

代码语言:javascript
复制
public abstract class BaseServer : IServer
{
    private readonly IPAddress ipAddress;

    private readonly int port;

    private readonly ILogger logger;

    protected BaseServer(
        string ipAddress, 
        int port,
        ILogger logger)
    {
        this.ipAddress = IPAddress.Parse(ipAddress);
        this.port = port;
        this.logger = logger;
    }

    public async Task StartAsync(CancellationToken token)
    {
        this.logger.Debug("[{0}] Listening for connections using: {1}:{2}", this.GetType().Name, this.ipAddress.ToString(), this.port);
        var tcpListener = new TcpListener(this.ipAddress, this.port);

        tcpListener.Start();

        while (!token.IsCancellationRequested)
        {
            await this.ServerProcessorAsync(tcpListener, token);
        }

        tcpListener.Stop();
        Console.WriteLine("Stopped Listener");
    }

    public abstract Task ServerProcessorAsync(TcpListener listener, CancellationToken token);
}

以下是服务器处理器:

代码语言:javascript
复制
public class Server : BaseServer
{
    private readonly ILogger logger;

    public Server(
        IAppConfiguration configuration,
        ILogger logger) 
        : base(configuration.IpAddress, configuration.Port, logger)
    {
        this.logger = logger;
    }

    public override async Task ServerProcessorAsync(TcpListener listener, CancellationToken token)
    {
        this.logger.Debug("[{0}] Waiting for connection...", this.GetType().Name);
        var client = await listener.AcceptTcpClientAsync();

        this.logger.Debug("[{0}] Spawning Thread for Connection...", this.GetType().Name);
        Parallel.Invoke(new ParallelOptions
            {
                CancellationToken = token,
                MaxDegreeOfParallelism = 10000,
                TaskScheduler = TaskScheduler.Current
            }, () => this.ListenToClient(client));
    }

    private void ListenToClient(TcpClient client)
    {
        var threadName = Thread.CurrentThread.Name;

        var bytes = new byte[2048];

        var stream = client.GetStream();

        int i;
        while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
        {
            var timeString = DateTime.Now.ToLongTimeString();
            var currentRes = Encoding.UTF8.GetString(bytes);
            var received = $"Recieved [{threadName}] [{timeString}]:  {currentRes}";

            this.logger.Info(received);
            var responseData = Encoding.UTF8.GetBytes(received);
            stream.Write(responseData, 0, responseData.Length);

        }

        client.Close();
    }
}

ctrl+c被按下时,这会正确地关闭应用程序吗?

是否有一种方法来调试这一点,或知道资源已被正确释放。

我假设while (!token.IsCancellationRequested)ctrl+c时会崩溃。我还假设,如果有任何由Parallel.Invoke创建的线程,它们将在调用Cancel时释放。

如果在这种情况下:

代码语言:javascript
复制
Console.CancelKeyPress += (sender, eventArgs) =>
{
     TokenSource.CancelAfter(500);
};

不等待事情被澄清,是否有一个比暂停更好的方法来确保一切都被正确地清理了?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-05-01 22:11:16

首先,您在订阅RunAsync事件之前先等待Console.CancelKeyPress事件,所以在为时已晚时您将订阅它。

第二,取消令牌在您的情况下是行不通的。这一行:

代码语言:javascript
复制
var client = await listener.AcceptTcpClientAsync();

将阻塞直到新客户端连接,并且由于AcceptTcpClientAsync没有接受CancellationToken的重载--因此不需要在整个程序中使用CancellationTokens。你应该做的是停止你的听众而不是取消。这将在上面的行上抛出异常,您应该捕获该异常并优雅地结束任务。

如果您真的想继续使用CancellationToken,即使这里并不真正需要它,请考虑使用这种方法来使它与AcceptTcpClientAsynchttps://stackoverflow.com/a/14524565/5311735一起工作。如果您使用CancellationToken来取消问题中没有显示的许多不同的操作,这也可能是个好主意。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36972381

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档