Со всей информацией, доступной из вопроса, вот что вы должны стремиться при использовании шаблона асинхронности / ожидания:
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
, скорее всего, освободит текущий поток (при условии, что на самом деле сделан вызов серверу), пока сервер не вернет ответ.
ТогдаИнфраструктура будет либо использовать существующий контекст синхронизации - , если вы находитесь в потоке пользовательского интерфейса, например, - или захватить поток из пула потоков - , если не - для запуска остальной части метода.
Вы даже можете немного уменьшить размер метода, просто вернув Task
с результатом типа AccountState
:
public Task<AccountState> GetAccountAsync(string key)
{
// The method SomeCommandSentToServerAsync must be changed to support async.
return _connection.SomeCommandSentToServerAsync(key);
}
В обоих примерах выhaver, чтобы сделать вызывающих async
, а также:
public async Task TheCallerAsync()
{
// Grab the key from somewhere.
string key = ...;
var accountState = await <inst>.GetAccountAsync(key);
// Do something with the state.
...
}
Превращение устаревшего метода в асинхронный метод
Теперь, что касается legacу SomeCommandSentToServer
метод.Есть способ дождаться этого устаревшего метода.Да, вы можете превратить этот метод в асинхронный метод, который можно использовать с async
/ await
.
Конечно, у меня нет всех деталей вашей реализации, но я надеюсь, что вы поймете, что нужно сделать.Магический класс для этого называется TaskCompletionSource .
То, что он позволяет вам сделать, это дать вам доступ к Task
.Вы создаете экземпляр этого класса TaskCompletionSource
, сохраняете его где-то, отправляете команду и сразу же возвращаете свойство Task этого нового экземпляра.
Как только вы получаете результат из потока опроса, вы получаетеэкземпляр TaskCompletionSource
, получить AccountState
и позвонить SetResult
с указанием состояния учетной записи.Это пометит задачу как выполненную и выполнит ту часть резюме, о которой вы просили:)
Вот идея:
public Task<AccountState> SomeCommandSentToServerAsync(string key)
{
var taskCompletionSource = new TaskCompletionSource<AccountState>();
// Find a way to keep the task in some state somewhere
// so that you can get it the polling thread.
// Do the legacy WinSock Send() command.
return taskCompletionSource.Task;
}
// This would be, I guess, your polling thread.
// Again, I am sure it is not 100% accurate but
// it will hopefully give you an idea of where the key pieces must be.
private void PollingThread()
{
while(must_still_poll)
{
// Waits for some data to be available.
// Grabs the data.
if(this_is_THE_response)
{
// Get the response and built the account state somehow...
AccountState accountState = ...
// Key piece #1
// Grab the TaskCompletionSource instance somewhere.
// Key piece #2
// This is the magic line:
taskCompletionSource.SetResult(accountState);
// You can also do the following if something goes wrong:
// taskCompletionSource.SetException(new Exception());
}
}
}