В .NET, в каком потоке будут обрабатываться события? - PullRequest
50 голосов
/ 17 марта 2010

Я попытался реализовать шаблон производитель / потребитель в c #. У меня есть поток потребителя, который контролирует общую очередь, и поток производителя, который помещает элементы в общую очередь. Поток производителя подписан на получение данных ... то есть он имеет обработчик событий и просто сидит и ждет события OnData для запуска (данные отправляются из стороннего API). Когда он получает данные, он помещает их в очередь, чтобы потребитель мог обработать их.

Когда событие OnData сработало в продюсере, я ожидал, что оно будет обработано моим потоком продюсера. Но похоже, что это не то, что происходит. Событие OnData выглядит так, как будто оно обрабатывается в новом потоке! Это так .net всегда работает ... события обрабатываются в своем собственном потоке? Могу ли я контролировать, какой поток будет обрабатывать события, когда они возникают? Что если сотни событий будут инициированы почти одновременно ... будет ли у каждого свой поток?

Ответы [ 4 ]

87 голосов
/ 17 марта 2010

Перечитав вопрос, я думаю, что теперь понимаю проблему. У вас есть что-то вроде этого:

class Producer
{
    public Producer(ExternalSource src)
    {
        src.OnData += externalSource_OnData;
    }

    private void externalSource_OnData(object sender, ExternalSourceDataEventArgs e)
    {
        // put e.Data onto the queue
    }
}

А потом у вас есть потребительский поток, который вытаскивает вещи из этой очереди. Проблема в том, что событие OnData вызывается вашим ExternalSource объектом - в любом потоке, в котором он выполняется.

C # event s - это, по сути, простая в использовании коллекция делегатов, а «запуск» события просто заставляет среду выполнения зацикливаться на всех делегатах и ​​запускать их по одному.

Таким образом, ваш обработчик событий OnData вызывается в любом потоке, в котором работает ExternalSource.

23 голосов
/ 17 марта 2010

Если вы не выполните маршалинг самостоятельно, событие будет выполняться в любом потоке, который его вызывает; нет ничего особенного в том, как вызываются события, и у вашего потока производителя нет обработчика событий, ваш поток производителя просто сказал «эй, когда вы запускаете это событие, вызовите эту функцию». Там нет ничего, что могло бы вызвать выполнение события в присоединяющемся потоке или в его собственном потоке (если только вы не должны были использовать BeginInvoke вместо обычного вызова делегата события, но это просто выполнит его в ThreadPool) .

9 голосов
/ 17 марта 2010

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

Для вызова события с помощью BeginInvoke используется ThreadPool. Вот некоторые мелкие детали

0 голосов
/ 17 марта 2010

Вы должны использовать обработчики autoresetevent для этой проблемы ..... в autoresetevent, когда производитель производит, он устанавливает сигнал, затем потребитель сбрасывает свой сигнал и потребляет .. после потребления потребляет установленный сигнал, тогда только произведенный производитель ...

AutoResetEvent pro = new AutoResetEvent(false);
AutoResetEvent con = new AutoResetEvent(true);

public void produser()
{

    while(true)
    {
        con.WaitOne();

        pro.Set();
    }
}

public void consumer()
{
    while (true)
    {
    pro.WaitOne();
       .................****

    con.Set();
    }
}

private void button1_Click(object sender, EventArgs e)
{
    Thread th1 = new Thread(produser);
    th1.Start();
    Thread th2 = new Thread(consumer);
    th2.Start();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...