我试图在c#中实现生产者/消费者模式。我有一个监视共享队列的消费者线程,以及一个将项放入共享队列的生产者线程。生产者线程被订阅接收数据...也就是说,它有一个事件处理程序,只是坐着等待OnData事件触发(数据从第三方api发送)。当它获取数据时,它会将其粘贴在队列中,以便消费者可以处理它。
当OnData事件在生产者中触发时,我原本期望它由我的生产者线程处理。但这似乎并不是正在发生的事情。 OnData事件看起来好像是在新线程上处理的!这是.net始终如何工作...事件是在自己的线程上处理的?我可以控制什么线程在它们被引发时处理事件?如果几乎同时引发了数百个事件......每个事件都有自己的线程吗?
答案 0 :(得分:87)
重新阅读问题之后,我想我现在明白了这个问题。你基本上得到了这样的东西:
class Producer
{
public Producer(ExternalSource src)
{
src.OnData += externalSource_OnData;
}
private void externalSource_OnData(object sender, ExternalSourceDataEventArgs e)
{
// put e.Data onto the queue
}
}
然后你有一个消费者线程从那个队列中拉出东西。问题是你的ExternalSource
对象触发了OnData事件 - 它正在运行的任何线程上。
C#event
s基本上只是一个易于使用的委托集合,“触发”事件只会导致运行时循环遍历所有委托并一次触发一个委托。
因此,在ExternalSource
正在运行的任何线程上调用OnData事件处理程序。
答案 1 :(得分:23)
除非你自己编组,否则一个事件将在任何调用它的线程上执行;调用事件的方式并没有什么特别之处,并且你的生产者线程没有事件处理程序,你的生产者线程简单地说“嘿,当你触发这个事件时,调用这个函数”。在那里没有任何东西导致事件执行发生在附加线程上,也没有发生在它自己的线程上(除非你使用BeginInvoke
而不是正常调用事件的委托,但这只会在{{{ 1}})。
答案 2 :(得分:9)
使用Invoke
引发事件与调用方法相同 - 它会在您引发它的同一个线程中执行。
使用BeginInvoke
举办活动会使用ThreadPool
。以下是一些minor details
答案 3 :(得分:-4)
你必须使用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();
}