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).
EDIT:
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.
Whenever I invoke the methods of an object running on thread A
Objects don't run on threads.
In order for this to work, you will have to create some kind of queue you can shove a delegate into that will be routinely checked thread A's main loop. Something like this, assuming that Something.MainThreadLoop is the entry point for thread A:
public class Something
{
private Queue<Action> actionQueue = new Queue<Action>();
private volatile bool threadRunning = true;
public void RunOnThread(Action action)
{
if (action == null)
throw new ArgumentNullException("action");
lock (actionQueue)
actionQueue.Enqueue(action);
}
public void Stop()
{
threadRunning = false;
}
private void RunPendingActions()
{
while (actionQueue.Count > 0) {
Action action;
lock (actionQueue)
action = actionQueue.Dequeue();
action();
}
}
public void MainThreadLoop()
{
while (threadRunning) {
// Do the stuff you were already doing on this thread.
// Then, periodically...
RunPendingActions();
}
}
}
Then, given a reference to a Something object, you could do this:
something.RunOnThread(() => Console.WriteLine("I was printed from thread A!"));
Code runs on threads. Objects aren't (generally - see thread local) bound to a particular thread. By doing WinFormControl.Invoke or WPFControl.Invoke, you are posting a message to the Message Pump or Dispatcher respectively, to run some code at a later date.
The message pump is something like this:
Message message;
while(GetMessage(&message))
{
ProcessMessage(message);
}
Microsoft has specifically built their UI controls and projects to allow the posting of messages across threads. Calling a method from thread A will always execute that method on thread A, even if it ends up doing some kind of asynchronous work and returning early.
Edit:
What it is I think you need is the Producer Consumer pattern.
http://msdn.microsoft.com/en-us/library/yy12yx1f(VS.80).aspx
Forget about consuming the messages from your main thread, which is what it sounds like you want to do. Consume from thread C.
Thread A is doing 'much more important things'. Thread B is spinning, listening for messages. Thread C is consuming those messages.
No need for marshalling across threads.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With