How can I notify the main thread of some message on another thread without blocking and waiting?

非 Y 不嫁゛ 提交于 2019-12-07 15:23:29

No, that's not possible. A thread has to go idle before you can inject code into it. That's done by, for example, Control.BeginInvoke (Windows Forms) or Dispatcher.BeginInvoke (WPF). These UI libraries often require code to be executed on the UI thread so they have explicit support for marshaling calls to the UI thread.

It is important for a thread to be in an "idle" state. You would have horrible re-entrancy problems if .NET supported some kind of asynchronous injection method.

If your component will be on a windows form, then here is one route to accomplishing your goal:

In your component code:

public event EventHandler MessageReceived;

private void UnsolicitedMessageReceived(...)
{
  if (MessageReceived != null)
  {
   // this will invoke on UI thread
   Parent.Invoke(MessageReceived, this, EventArgs.Empty);
  }
}

In your form you might have:

MyCoolComponent1.MessageReceived += new EventHandler(MessageReceived);

private void MessageReceived(object sender, EventArgs e)
{
  // do some stuff here
}

Since you probably don't want the thread to just drop what they're currently doing, you'll need some sort of task queue for the thread to look at - this doesn't have to be any more advanced than a Queue, where T is some type you use to represent each task. Maintain a queue and add the messages there, so the threads can then process them whenever they're done with what they're currently doing.

Use a semaphore to let your worker thread wait for new data if the queue is empty, and pulse on that semaphore if you add a new message to an empty queue. That prevents them from wasting CPU cycles on constantly polling the queue.

If you want several worker threads, all you need to do is make sure each thread has its own queue, and you'll be in full control over which thread runs what.

EDIT: On reading the question again, I'm not sure if your problem is that you really need the thread to do some work immediately. If that's the case, I can't see this being possible, since you can't just inject code at a random time - you'd most likely break whatever was executing at that point.

One option is to pass a delegate from your main thread to the child threads that they can use as a callback to signal that they have a message. The child threads can pass the message through the callback, which saves the message in a memory-based collection or to persistent storage, and the main thread checks this when appropriate.

You could take this one step further and not have the child threads signal the main thread at all, but instead have the child threads write the messages to a database, and have the main thread check the database when it's convenient. You can even use the database (through transactions) to handle concurrency. And this gives the advantage of not losing messages if the system crashes. Even lets you spread child threads (or main threads) across servers.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!