Как дождаться ответа одного из методов обратного вызова перед продолжением кода? - PullRequest
0 голосов
/ 17 июня 2020

В настоящее время я работаю над системой, которая активно отслеживает информацию о серверах. Для некоторых методов мне нужно, чтобы они были асинхронными, однако есть несколько, которые реализованы синхронным образом (внешняя библиотека). У меня есть этот код:

m_ServerQuery = HServerQuery.Invalid;

m_PingResponse = new ISteamMatchmakingPingResponse(OnServerResponded, OnServerFailedToRespond);
try
{
    m_ServerQuery = SteamMatchmakingServers.PingServer((uint)ip, port, m_PingResponse);
    await Task.Delay(500);
    SteamMatchmakingServers.CancelServerQuery(m_ServerQuery);
}
    catch
{
    Console.WriteLine($"*** Something went wrong while pinging server ***");
}

Как вы можете видеть из фрагмента кода выше, класс PingResponse наследует два метода, которые работают как «обратный вызов», когда ответ отправляется из Steam. Теперь ожидание 0,5 миллисекунды работает, однако я думаю, что было бы лучше реализовать его, чтобы дождаться срабатывания одного из этих двух методов: OnServerResponded, OnServerFailedToRespond Как я смогу достичь этого? Определение ISteamMatchmakingPingResponse:

public class ISteamMatchmakingPingResponse
{
    public ISteamMatchmakingPingResponse(ServerResponded onServerResponded, ServerFailedToRespond onServerFailedToRespond);

    ~ISteamMatchmakingPingResponse();

    public static explicit operator IntPtr(ISteamMatchmakingPingResponse that);

    public delegate void ServerResponded(gameserveritem_t server);
    public delegate void ServerFailedToRespond();
}

1 Ответ

0 голосов
/ 17 июня 2020

Я предполагаю, что OnServerResponded и OnServerFailedToRespond - это функции, которые вы можете изменять. Вы можете использовать TaskCompletionSource<bool> и дождаться его задачи. Что-то вроде этого.

TaskCompletionSource<bool> pingSucceed;

//Not sure about the firm of your callback functions, just a void function for this example
void OnServerResponded()
{
    //Do any task you need to do
    //..

    if(pingSucceed != null)
        pingSucceed.TrySetResult(true);
}

void OnServerFailedToRespond()
{
    //Do any task you need to do
    //..

    if(pingSucceed != null)
        pingSucceed.TrySetResult(false);
}

//Now the call
async Task TheFunctionThatPingsTheServer()
{
    //Do any task you need to do prior to the ping
    //..

    pingSucceed = new TaskCompletionSource<bool>();
    m_ServerQuery = SteamMatchmakingServers.PingServer((uint)ip, port, m_PingResponse);
    var succeed = await pingSucceed.Task;
    pingSucceed.Dispose();
    pingSucceed = null;

    //Here succeed will be true if server answered, else false.

}

Остерегайтесь этого, если OnServerResponded и / или OnServerFailedToRespond выполняются в разных потоках, вы должны защитить все доступы к pingSucceed, заблокировав объект, чтобы избежать состояния гонки .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...