首页 > 解决方案 > 将 Task.Run 中的代码编组到调用线程

问题描述

我正在使用Task.Run. 我将它存储Task在服务器类中的一个字段中,以便将来如果需要可以取消它。一旦Task启动,我就会启动一个同步运行状态的游戏引擎。

private void ListenForConnection()
{
    this.listeningTokenSource = new CancellationTokenSource();
    this.listeningTask = Task.Run(async () =>
    {
        while (!this.IsDeleted)
        {
            Socket clientSocket = await this.serverSocket.AcceptAsync();
            await this.CreatePlayerConnection(clientSocket);
        }
    }, this.listeningTokenSource.Token);
}

private async Task CreatePlayerConnection(Socket clientConnection)
{
    IServerConnection playerConnection = await this.connectionFactory.CreateConnection(clientConnection);
    IPlayer player = await this.playerFactory.CreatePlayer(playerConnection);
    if (playerConnection is TcpConnection tcpConnection)
    {
        tcpConnection.SetPlayer(player);
    }

    this.connectedPlayers.Add(player);
    await this.PlayerConnected(player);

    await player.ExecuteCommand(this.InitialCommand);
}

在这种情况下,如果玩家连接到服务器,我将 Socket 传递给一个IServerConnection实例并将其分配给玩家。当客户端命令通过套接字发送时,IServerConnection该客户端接收到它会解析它,然后在管道中的某个地方它会想要在此之外修改游戏状态IServerConnection;通过与引擎内运行的实体进行交互(甚至可能在另一个线程本身上)。

这一切都发生在netcoreapp2.0控制台应用程序中。

当客户端套接字进入不同线程中的触摸状态时,我会遇到源自后台操作的客户端套接字问题吗?在 WPF 和 aspnet 中,我过去使用过 SynchronizationContext,但控制台应用程序没有这个。

什么是一种干净的方法来确保我不会到处死锁,而不必到处乱扔锁。我可以在启动ListenForConnection()任务之前捕获当前线程并将状态更改回原始线程吗?

标签: multithreading.net-core

解决方案


从我的角度来看,您总是会得到一个公共资源,该资源将由不同的线程更新。所以使用 alock是可行的方法。但是,如果您将资源和锁包装在一个对象中,您可以将所有synchronization操作保存在本地。

public class Resource{
    public int Value{get;set;}
}

public class Engine
{
   private Resource commonResource=new Resource();
   private object @lock=new object();
   public void  ChangeResource(int newvalue)
   {
      lock(@lock)
      {
        this.commonResource.Value=newvalue;
      }
   }
}
public class Client{
    private Engine engine;
    public Client(Engine engine)
    {
        this.engine=engine;
    }
    public void ChangeResource(int newValue){
        this.engine.ChangeResource(newvalue);
    }
}

PS我不知道你如何使用你的引擎/包装器(无论你说客户端进行更改是什么)所以我只是将它注入所有客户端。你也可以使用singleton。如果您运行async操作,请考虑使用SempahoreSlim而不是锁。


推荐阅读