我正在尝试创建一个函数,该函数在被调用时将信息返回给服务器上的调用者。我在此函数中想要的是,它创建了一个线程,该线程将命令发送给服务器,然后挂起自身,直到服务器返回答案为止。
public AccountState GetAccount(string key)
{
AccountState state = null;
Thread t = new Thread(() =>
{
_connection.SomeCommandSentToServer(key);
accountRequests.TryAdd(key, (Thread.CurrentThread, null));
//Suspend current thread until ServerReponseHere is called
Thread.CurrentThread.Suspend();
//We have been resumed, value should be in accountRequests now
accountRequests.TryRemove(key, out var item);
state = item.AccountState;
});
t.Start();
return state;
}
public ConcurrentDictionary<string, (Thread Thread, AccountState AccountState)> accountRequests = new ConcurrentDictionary<string, (Thread Thread, AccountState AccountState)>();
///Once server is done with processed command, call to this function made
public void ServerReponseHere(string key, AccountState state)
{
accountRequests.TryGetValue(username, out var item);
accountRequests.TryUpdate(username, (item.Thread, new AccountState()), item);
item.Thread.Resume();
}
然后我的想法是,在另一个函数中,服务器响应时,它将调用上面显示的ResumeThread函数。
C#说Suspend / Resume是已弃用的函数,-有什么更好的方法呢?
有关“ SomeCommandSentToServer”的说明-这只是通过TCP套接字向服务器发送命令。
在该呼叫中,真正发生的只是向服务器的传输。我正在使用使用WinSock2.h调用“ Send()”的库-是的,我知道这是一个已弃用的库...但是我使用的库需要它。
我有一个单独的线程从服务器轮询输入。因此,我无法在此SomeCommandSentToServer上“等待”-我需要等待某种回调函数(即我刚才提到的恢复函数)-才能完成此工作。
我不确定该怎么做
答案 0 :(得分:3)
使用问题中的所有可用信息,这是使用异步/等待模式时的目标:
public async Task<AccountState> GetAccountAsync(string key)
{
// The method SomeCommandSentToServerAsync must be changed to support async.
AccountState state = await _connection.SomeCommandSentToServerAsync(key);
return state;
}
您极不可能需要其他任何东西。那样的话,我的意思是您不必,因为从维护的角度看这很可怕,您将不必直接操作线程,将它们放入并发字典中并手动暂停或恢复它们;)
.NET将负责线程部分,这意味着async
基础结构的魔力很可能会释放当前线程(假设实际上已对服务器进行了调用),直到服务器返回响应为止。 / p>
然后,基础结构将使用现有的同步上下文-(例如,如果您在UI线程上)-,或从线程池中获取线程-(如果不是)-运行其余方法。
您甚至可以通过简单地返回类型为Task
的{{1}}来减小方法的大小:
AccountState
在两个示例中,您也将不得不使呼叫者成为public Task<AccountState> GetAccountAsync(string key)
{
// The method SomeCommandSentToServerAsync must be changed to support async.
return _connection.SomeCommandSentToServerAsync(key);
}
:
async
将传统方法转换为异步方法
现在,关于旧式public async Task TheCallerAsync()
{
// Grab the key from somewhere.
string key = ...;
var accountState = await <inst>.GetAccountAsync(key);
// Do something with the state.
...
}
方法。有一种方法可以等待该旧方法。是的,您可以将该方法转换为可以与SomeCommandSentToServer
/ async
一起使用的异步方法。
当然,我没有实现的所有细节,但希望您能了解需要做些什么。实现这一目标的神奇类称为TaskCompletionSource。
它允许您执行的操作是让您访问await
。创建该Task
类的实例,将其保留在某个地方,发送命令并立即返回该新实例的Task属性。
一旦从轮询线程获得结果,就将抓取TaskCompletionSource
的实例,获取TaskCompletionSource
并以帐户状态致电AccountState
。这会将任务标记为已完成,然后执行您要求的简历部分:)
这里是个主意:
SetResult