C#挂起线程,直到服务器响应

时间:2018-09-29 21:35:12

标签: c# multithreading async-await resume suspend

我正在尝试创建一个函数,该函数在被调用时将信息返回给服务器上的调用者。我在此函数中想要的是,它创建了一个线程,该线程将命令发送给服务器,然后挂起自身,直到服务器返回答案为止。

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上“等待”-我需要等待某种回调函数(即我刚才提到的恢复函数)-才能完成此工作。

我不确定该怎么做

1 个答案:

答案 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
相关问题