Как заблокировать до завершения асинхронного вызова? - PullRequest
1 голос
/ 22 декабря 2009

У меня есть метод, который вызывает асинхронный метод, и обратный вызов, который запускается после завершения асинхронного метода.

Я хочу, чтобы мой метод отображался синхронно, поэтому я создал AutoResetEvent, который называется асинхронным методом, вызов WaitOne () для экземпляра AutoResetEvent и я вызываю Set () в методе обратного вызова. Примерно так (упрощенно для этого примера):

private System.Threading.AutoResetEvent waitRun_m;
public void RunSynchronous()
{
    waitRun_m = new System.Threading.AutoResetEvent(false);
    CallAsynchronousMethod();

    waitRun_m.WaitOne();
}

private void Callback()
{
    waitRun_m.Set();
}

Теперь можно ли завершить вызов CallAsynchronousMethod до вызова WaitOne (), вызывая вызов Set () перед WaitOne (). Есть ли лучший способ сделать это, чтобы избежать этой потенциальной проблемы?

Ответы [ 3 ]

7 голосов
/ 22 декабря 2009

Я верю, что это ответит на ваш вопрос:

Вызов Set устанавливает AutoResetEvent для освобождения ожидающего потока. AutoResetEvent остается сигнальным до тех пор, пока не будет освобожден единственный ожидающий поток, а затем автоматически возвращается в состояние без сигнализации Если нет ожидающих потоков, состояние остается неопределенным.

Вы должны быть осторожны, потому что теперь RunSynchronous не выглядит потокобезопасным. Если два разных потока вызывают его перекрывающимся образом, весь ад может вырваться на свободу.

3 голосов
/ 22 декабря 2009

Это не проблема, событие, получающее Set перед вашим WaitOne, полностью поддерживается. AutoResetEvent был бы совершенно непригодным, если бы это было не так.

1 голос
/ 22 декабря 2009

Как сказал Дэниел и Нобугз, использование AutoResetEvent может быть опасным. Вы можете звонить waitRun_m.Set(); перед вызовом waitRun_m.WaitOne();, когда асинхронная операция очень короткая. Я бы предпочел что-то подобное. Таким образом, вы уверены, что сначала войдете в состояние ожидания, а затем вызовете метод Pulse. Кроме того, вам не нужно Close AutoResetEvent, который часто забывают.

private readonly object m_lock = new object();
public void RunSynchronous()
{
    lock(m_lock) {
        CallAsynchronousMethod();
        Monitor.Wait(m_lock);
    }
}

private void Callback()
{
    lock(m_lock)
        Monitor.Pulse(m_lock);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...