我正在使用Task.Run
将带有Socket的网络服务器分解为后台进程。我将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()
任务之前将当前线程捕获,然后将封送状态更改回原来的线程吗?
答案 0 :(得分:0)
从我的角度来看,您总是会得到一个公共资源,该资源将由不同的线程进行更新。因此,使用lock
是可行的方法。但是,如果将资源和锁包装在一个对象中您可以将所有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 我不知道您如何使用您的Engine / wrapper(无论您说客户端如何进行更改),所以我只是将其注入所有客户端中。您可以使用{{ 1}}。
如果您运行singleton
操作,请考虑使用SempahoreSlim而不是锁。