Может ли заблокированный поток запускать события?

У меня есть программа, которая порождает поток, управляющий последовательной связью. Пока он ожидает ответа на последовательном порту, я блокирую поток с помощью AutoResetEvent.

Не сможет ли этот поток выполнить событие при получении данных, потому что он заблокирован?

Чтобы проиллюстрировать это, у меня есть простая версия моего кода ниже. Приведет ли этот код к тупиковой ситуации или событие может запуститься в заблокированном потоке, в конечном итоге проснувшись?

AutoResetEvent rxDataReady = new AutoResetEvent(false);

public void GetSomeDataFromSerialPort()
{
    SerialPort sp = new SerialPort()
    sp.Write(dataRequest)

    rxDataReady.WaitOne();

    // Process data
}

private void ReadDataEventHandler(object sender, SerialDataReceivedEventArgs e)
{
    // Prepare data
    rxDataReady.Set();
}

Большое Вам спасибо


person folmerbrem    schedule 13.12.2016    source источник


Ответы (2)


Примечания от MSDN SerialPort.DataReceived

Событие DataReceived вызывается в вторичном потоке при получении данных от объекта SerialPort.

Поэтому я не думаю, что ваш пример кода приведет к взаимоблокировке.

Тем не менее, ответ на ваш вопрос в заголовке:

Может ли заблокированный поток запускать события?

No.

person Diryboy    schedule 13.12.2016

Чтобы ответить на вопрос в заголовке: Нет. Заблокированный поток не может вызвать событие. Однако, если за инициирование события отвечает другой поток, он должен работать должным образом.

Чтобы проиллюстрировать это, вот пример:

internal class Program
{
    private static readonly AutoResetEvent RxDataReady = new AutoResetEvent(false);

    private static event EventHandler ev;

    public static void GetSomeDataFromSerialPort()
    {
        RxDataReady.WaitOne();

        // Process data
    }

    private static void Main()
    {
        ev += ReadDataEventHandler;
        Task.Run(
            async () =>
                {
                    await Task.Delay(5000);
                    ev(null, EventArgs.Empty);
                });
        GetSomeDataFromSerialPort();

        Console.WriteLine("Done.");
        Console.ReadLine();
    }

    private static void ReadDataEventHandler(object sender, EventArgs eventArgs)
    {
        // Prepare data
        RxDataReady.Set();
    }
}

Что делает этот код, так это просто запускает новый поток, который ждет 5 секунд, а затем вызывает событие. Если вы попытаетесь запустить это, вы увидите, что через 5 секунд «Готово». отображается в консоли.

Если бы вы подняли событие в том же потоке:

 private static void Main()
    {
        ev += ReadDataEventHandler;
        GetSomeDataFromSerialPort();
        ev(null, EventArgs.Empty);

        Console.WriteLine("Done.");
        Console.ReadLine();
    }

Тогда событие никогда не будет вызвано, и выполнение никогда не продолжится после RxDataReady.WaitOne().

Альтернативой этому может быть запуск GetSomeDataFromSerialPort() в другом потоке.

person eitamal    schedule 13.12.2016
comment
Ответ @Diryboy лучше, поскольку он касается SerialPort.DataReceived, в частности, где я даю более общий ответ. - person eitamal; 13.12.2016