Rushyo Rushyo - 1 year ago 88
C# Question

C# non-UI cross-thread invocation

I'm trying to make cross-threaded calls in C#.

Whenever I invoke the methods of an object created in the context of thread A from a static method called from thread B, the method always runs in thread B. I don't want that, I want it run on the same thread as the thread A object whose methods I am calling.

Invoke works fine for UI calls and I've read dozens of articles and SO answers relating to different ways of making cross-threaded Forms/WPF calls. However whatever I try (event handling, delegates, etc) Thread A's object's method will always run in Thread B if it is invoked by Thread B.

What part of the library should I be looking in to solve this? If it's relevant, Thread B currently 'spins', reads from a network port and occasionally invokes Thread A's object's method through a delegate that was created in Thread A and passed in using a ParameterizedThreadStart.

I'm not looking to change paradigm, just send a message (a request to invoke a method) from one thread (Thread B) to another (Thread A).


My question was 'what part of the library should I be looking in to solve this?' The answer appears to be none. If I want to clearly delineate consumption and polling I'll have to write my own code to handle that.

Answer Source

EDIT: I think you probably want to use the System.Threading.AutoResetEvent class. The MSDN documentation has a decent example of one thread waiting on the other that I think is similar to what you are trying to do: In particular, pay attention to the calls to trigger.WaitOne() and trigger.Set()

EDIT2: Added option #3 after reading new comment from OP.

"Whenever I invoke the methods of an object running on thread A ..." - An object doesn't "run" on a thread and isn't really owned by any thread, regardless of what thread created the object.

Given that your question is regarding "non-UI cross-thread invocation", I assume you are already familiar with "UI cross-thread invocation". I can see how WinForms would give you an impression that a thread owns an object and that you need to "send a message" to a thread in order to make it do something.

WinForm control objects are kind of a special case in that they simply don't function properly if you interact with them with a thread that isn't the one that created them, but that's not caused by the way that threads and objects interact.

Anyway, on to addressing your question.

First, a question to clarify the problem: You've mentioned what Thread B is doing, but what is Thread A doing prior to being "invoked" by Thread B?

Here are a couple of ideas that I think are along the lines of what you want to do:

  1. Don't create Thread A until you need to. Instead of having Thread B "send a message to Thread A", rather have Thread B create Thread A (or call it Thread C if you prefer) and make it start executing at that time.

  2. If you need Thread A to already exist and you only want Thread A to handle Thread B's events one at a time, you could have Thread A wait until it receives a notification from Thread B. Take a look at the System.Threading.WaitHandle class (derived classes of interest are ManualResetEvent and AutoResetEvent).

    Thread A will at some point call WaitHandle.WaitOne(), which will cause it to pause and wait until Thread B calls WaitHandle.Set() on the same WaitHandle object.

  3. If Thread A is busy doing other things, then you might want to set up some kind of flag variable. Similar to the WaitHandle concept in #2, but instead of causing Thread A to pause, you just want Thread B to set a flag (perhaps just a boolean variable) that will signal to Thread A that it needs to do something. While Thread A is busy doing other things, it can periodically check that flag to decide whether or not there is work that needs to be done.

Does the method that Thread A will execute on your object require any input from Thread B? Then before Thread B calls WaitHandle.Set(), have it stick some data into a queue or something. Then, when Thread A is "activated", it can retrieve that data from the queue and proceed to execute the object's method using that data. Use a lock mechanism (i.e. the C# lock statement) to synchronize access to the queue.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download