How to post messages to an STA thread running a message pump? - c#

So, following this, I decided to explicitly instantiate a COM object on a dedicated STA thread. Experiments showed that the COM object needed a message pump, which I created by calling Application.Run():
private MyComObj _myComObj;
// Called from Main():
Thread myStaThread = new Thread(() =>
{
_myComObj = new MyComObj();
_myComObj.SomethingHappenedEvent += OnSomthingHappened;
Application.Run();
});
myStaThread.SetApartmentState(ApartmentState.STA);
myStaThread.Start();
How do I post messages the the STA thread's message pump from other threads?
Note:
I heavily edited the question for the sake of brevity. Some parts of #Servy's answer now seems unrelated, but they were for the original question.

Keep in mind that the message queue that Windows creates for an STA thread is already an implementation of a thread-safe queue. So just use it for your own purposes. Here's a base class that you can use, derive your own to include your COM object. Override the Initialize() method, it will be called as soon as the thread is ready to start executing code. Don't forget to call base.Initialize() in your override.
It you want to run code on that thread then use the BeginInvoke or Invoke methods, just like you would for the Control.Begin/Invoke or Dispatcher.Begin/Invoke methods. Call its Dispose() method to shut down the thread, it is optional. Beware that this is only safe to do when you are 100% sure that all COM objects are finalized. Since you don't usually have that guarantee, it is better that you don't.
using System;
using System.Threading;
using System.Windows.Forms;
class STAThread : IDisposable {
public STAThread() {
using (mre = new ManualResetEvent(false)) {
thread = new Thread(() => {
Application.Idle += Initialize;
Application.Run();
});
thread.IsBackground = true;
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
mre.WaitOne();
}
}
public void BeginInvoke(Delegate dlg, params Object[] args) {
if (ctx == null) throw new ObjectDisposedException("STAThread");
ctx.Post((_) => dlg.DynamicInvoke(args), null);
}
public object Invoke(Delegate dlg, params Object[] args) {
if (ctx == null) throw new ObjectDisposedException("STAThread");
object result = null;
ctx.Send((_) => result = dlg.DynamicInvoke(args), null);
return result;
}
protected virtual void Initialize(object sender, EventArgs e) {
ctx = SynchronizationContext.Current;
mre.Set();
Application.Idle -= Initialize;
}
public void Dispose() {
if (ctx != null) {
ctx.Send((_) => Application.ExitThread(), null);
ctx = null;
}
}
private Thread thread;
private SynchronizationContext ctx;
private ManualResetEvent mre;
}

Is there a way to start the message pump so it does not block?
No. The point of a message queue is that it needs to consume the thread's execution. A message queue is, in implementation, going to look very similar to your:
while(!_stopped)
{
var job = _myBlockingCollection.Take(); // <-- blocks until some job is available
ProcessJob(job);
}
That is a message loop. What you're trying to do is run two different message loops in the same thread. You can't really do that (and have both queues pumping; one queue will, by necessity, pause execution of the other while it is running), it just doesn't make sense.
What you need to do, instead of creating a second message loop on the same thread, is send messages to your existing queue. One way of doing that is through the use of a SynchronizationContext. One problem however is that there aren't any events that can be hooked into to execute a method in the message pump with that overload of Run. We'll need to show a Form just so that we can hook into the Shown event (at which point we can hide it). We can then grab the SynchronizationContext and store it somewhere, allowing us to use it to post messages to the message pump:
private static SynchronizationContext context;
public static void SendMessage(Action action)
{
context.Post(s => action(), null);
}
Form blankForm = new Form();
blankForm.Size = new Size(0, 0);
blankForm.Shown += (s, e) =>
{
blankForm.Hide();
context = SynchronizationContext.Current;
};
Application.Run(blankForm);

Related

Notify when thread is complete, without locking calling thread

I am working on a legacy application that is built on top of NET 3.5. This is a constraint that I can't change.
I need to execute a second thread to run a long running task without locking the UI. When the thread is complete, somehow I need to execute a Callback.
Right now I tried this pseudo-code:
Thread _thread = new Thread(myLongRunningTask) { IsBackground = True };
_tread.Start();
// wait until it's done
_thread.Join();
// execute finalizer
The second option, which does not lock the UI, is the following:
Thread _thread = new Thread(myLongRunningTask) { IsBackground = True };
_tread.Start();
// wait until it's done
while(_thread.IsAlive)
{
Application.DoEvents();
Thread.Sleep(100);
}
// execute finalizer
Of course the second solution is not good cause it overcharge the UI.
What is the correct way to execute a callback when a _thread is complete? Also, how do I know if the thread was cancelled or aborted?
*Note: * I can't use the BackgroundWorker and I can't use the Async library, I need to work with the native thread class.
There are two slightly different kinds of requirement here:
Execute a callback once the long-running task has completed
Execute a callback once the thread in which the long-running task was running has completed.
If you're happy with the first of these, the simplest approach is to create a compound task of "the original long-running task, and the callback", basically. You can even do this just using the way that multicast delegates work:
ThreadStart starter = myLongRunningTask;
starter += () => {
// Do what you want in the callback
};
Thread thread = new Thread(starter) { IsBackground = true };
thread.Start();
That's very vanilla, and the callback won't be fired if the thread is aborted or throws an exception. You could wrap it up in a class with either multiple callbacks, or a callback which specifies the status (aborted, threw an exception etc) and handles that by wrapping the original delegate, calling it in a method with a try/catch block and executing the callback appropriately.
Unless you take any special action, the callback will be executed in the background thread, so you'll need to use Control.BeginInvoke (or whatever) to marshal back to the UI thread.
I absolutely understand your requirements, but you've missed one crucial thing: do you really need to wait for the end of that thread synchronously? Or maybe you just need to execute the "finalizer" after thread's end is detected?
In the latter case, simply wrap the call to myLongRunningTask into another method:
void surrogateThreadRoutine() {
// try{ ..
mytask();
// finally { ..
..all 'finalization'.. or i.e. raising some Event that you'll handle elsewhere
}
and use it as the thread's routine. That way, you'll know that the finalization will occur at the thread's and, just after the end of the actual job.
However, of course, if you're with some UI or other schedulers, the "finalization" will now run on yours thread, not on the "normal threads" of your UI or comms framework. You will need to ensure that all resources are external to your thread-task are properly guarded or synchronized, or else you'll probably clash with other application threads.
For instance, in WinForms, before you touch any UI things from the finalizer, you will need the Control.InvokeRequired (surely=true) and Control.BeginInvoke/Invoke to bounce the context back to the UI thread.
For instance, in WPF, before you touch any UI things from the finalizer, you will need the Dispatcher.BeginInvoke..
Or, if the clash could occur with any threads you control, simple proper lock() could be enough. etc.
You can use a combination of custom event and the use of BeginInvoke:
public event EventHandler MyLongRunningTaskEvent;
private void StartMyLongRunningTask() {
MyLongRunningTaskEvent += myLongRunningTaskIsDone;
Thread _thread = new Thread(myLongRunningTask) { IsBackground = true };
_thread.Start();
label.Text = "Running...";
}
private void myLongRunningTaskIsDone(object sender, EventArgs arg)
{
label.Text = "Done!";
}
private void myLongRunningTask()
{
try
{
// Do my long task...
}
finally
{
this.BeginInvoke(Foo, this, EventArgs.Empty);
}
}
I checked, it's work under .NET 3.5
You could use the Observer Pattern, take a look here:
http://www.dofactory.com/Patterns/PatternObserver.aspx
The observer pattern will allow you, to notify other objects which were previously defined as observer.
A very simple thread of execution with completion callback
This does not need to run in a mono behavior and is simply used for convenience
using System;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
public class ThreadTest : MonoBehaviour
{
private List<int> numbers = null;
private void Start()
{
Debug.Log("1. Call thread task");
StartMyLongRunningTask();
Debug.Log("2. Do something else");
}
private void StartMyLongRunningTask()
{
numbers = new List<int>();
ThreadStart starter = myLongRunningTask;
starter += () =>
{
myLongRunningTaskDone();
};
Thread _thread = new Thread(starter) { IsBackground = true };
_thread.Start();
}
private void myLongRunningTaskDone()
{
Debug.Log("3. Task callback result");
foreach (int num in numbers)
Debug.Log(num);
}
private void myLongRunningTask()
{
for (int i = 0; i < 10; i++)
{
numbers.Add(i);
Thread.Sleep(1000);
}
}
}
Try to use ManualRestEvent to signal of thread complete.
Maybe using conditional variables and mutex, or some functions like wait(), signal(), maybe timed wait() to not block main thread infinitely.
In C# this will be:
void Notify()
{
lock (syncPrimitive)
{
Monitor.Pulse(syncPrimitive);
}
}
void RunLoop()
{
for (;;)
{
// do work here...
lock (syncPrimitive)
{
Monitor.Wait(syncPrimitive);
}
}
}
more on that here:
Condition Variables C#/.NET
It is the concept of Monitor object in C#, you also have version that enables to set timeout
public static bool Wait(
object obj,
TimeSpan timeout
)
more on that here:
https://msdn.microsoft.com/en-us/library/system.threading.monitor_methods(v=vs.110).aspx

How do I avoid a race condition when using Dispatcher.Run()?

I've found little information on how to properly use the Dispatcher class on its own.
Currently I am using it similar to this question, but there is an inherent race condition which I do not see mentioned anywhere.
Assuming you use the following code to start a dispatcher thread:
Thread thread = new Thread(Dispatcher.Run);
thread.Start();
And try to use it later:
Dispatcher.FromThread(thread).Invoke(MyMethodDelegate);
This will often throw a NullReferenceException as the Dispatcher.FromThread call may return null since there is no guarantee that Dispatcher.Run has been called yet.
What I've done to implement this properly is to use a signal to ensure the dispatcher is running before continuing to use it on the main thread.
This is a shorter version, done as a utility function, inspired by yours so I left out the comments.
private static Thread CreateDispatcherThread()
{
using (var startedEvent = new ManualResetEventSlim())
{
var dispatcherThread = new Thread( _ => {
Dispatcher.CurrentDispatcher.BeginInvoke((Action)(startedEvent.Set));
Dispatcher.Run(); } );
dispatcherThread.Start();
startedEvent.WaitHandle.WaitOne();
return dispatcherThread;
}
}
Here is what I ended up doing, which is what I believe you need to do in order to use the Dispatcher properly.
private Thread executionThread;
private object SyncObject {get;set;}
private delegate void DispatcherMethod();
private void InitDispatcher()
{
this.SyncObject = new object();
// Set up the dispatcher pump. See Dispatcher.Run on MSDN.
this.executionThread = new Thread(StartDispatcher);
lock (this.SyncObject)
{
this.executionThread.Start();
Monitor.Wait(this.SyncObject);
}
}
private void StartDispatcher()
{
DispatcherMethod method = DispatcherStarted;
// Enqueue a started event by adding an initial method on the message pump.
// Use BeginInvoke because the dispatcher is not actually running yet.
// The call to Dispatcher.CurrentDispatcher handles creating the actual
// Dispatcher instance for the thread (see MSDN - Dispatcher.FromThread
// does not initialize the Dispatcher).
Dispatcher.CurrentDispatcher.BeginInvoke(method);
Dispatcher.Run();
}
private void DispatcherStarted()
{
lock (this.SyncObject)
{
Monitor.Pulse(this.SyncObject);
}
}
After InitDispatcher returns, you can use
Dispatcher.FromThread(executionThread).Invoke
or
Dispatcher.FromThread(executionThread).BeginInvoke
to marshal calls to the dispatcher thread.

Queueing Operation

im sending smses using dll, that dll have some events one them is
Session_OnMessageAccepted
inside that im doing something like this
void Session_OnMessageAccepted(object sender,EventArgs e)
{
new Thread(
delegate()
{
//do stuff
}).Start();
}
this is ok only problem is the code inside dostuff gets excuted same time , is there is any chance i can put "dostuff"in a queue and make it happen synchronously?
You're looking for the ConcurrentQueue class.
You can add the messages in the queue. And you can have a separate thread started(On App Start) which will continuously look for messages in the queue and process it.
i.e in the thread method
while(true)
{
//check if the queue is empty otherwise continue;
//fetch the element
//process it
}
A Note About The ThreadPool
As a general comment to your current code, consider using ThreadPool.QueueUserWorkItem rather than creating new threads.
Queuing work items to the ThreadPool is much more efficient than creating new threads for short term tasks. The ThreadPool maintains a pool of existing threads and re-uses them. Creating and managing threads is expensive so should be avoided when needing many short-lived tasks. As well as being efficient, the ThreadPool also has natural queuing behaviour.
However, using the ThreadPool does not guarantee that items are executed in the order you queued them, and may also result in items being executated at the same time i.e. concurrently. Therefore the ThreadPool doesn't help you out for this particular quesiton.
Example Message Processing Loop
The following is a message processing loop pattern which allows operations to be queued and then processing on a separate thread serially.
public class SomeClass
{
private readonly object _syncObj = new object();
private readonly Thread _thread;
private readonly Queue<Action> _queue = new Queue<Action>();
private readonly ManualResetEvent _messageAccepted = new ManualResetEvent(false);
public SomeClass()
{
_thread = new Thread(() =>
{
while (true)
{
Action operation;
while (TryDequeue(out operation))
{
operation();
}
_messageAccepted.WaitOne();
}
}) {IsBackground = true};
_thread.Start();
}
private void Session_OnMessageAccepted(object sender, EventArgs e)
{
Action operation = () =>{/* Do stuff */};
Enqueue(operation);
}
private void Enqueue(Action operation)
{
lock (_syncObj)
{
_queue.Enqueue(operation);
_messageAccepted.Set();
}
}
private bool TryDequeue(out Action operation)
{
lock (_syncObj)
{
operation = (_queue.Count != 0) ? _queue.Dequeue() : null;
if (operation == null) _messageAccepted.Reset();
return (operation != null);
}
}
}

How to construct a new WPF form from a different thread in c#

I'm having trouble with the concept of threads and how to use them.
I'm trying to code a fairly basic chat program (as part of a larger program) and it currently works like this:
The 'NetworkSession' class receives the input from the server on a separate thread in a loop. If it receives input that indicates it should open a new chat window it constructs a new WPF class (ChatWindow) and displays it.
Originally I got the error that "The calling thread must be STA, because many UI components require this.". So i set the thread to be STA but now of course the WPF form is unusable because its running on the same thread as the blocking loop.
So my question is how do I create a new instance of a WPF form from within another thread.
I've seen alot of discussion about this but it tends to deal with running a delegate from a form that has already been constructed.
Here is some code.
while (Connected) //this loop is running on its own thread
{
Resp = srReceiver.ReadLine();
if (Resp.StartsWith("PING")) SendToServer("PONG");
if (Resp.StartsWith("CHAT FROM"))
{
String[] split = Resp.Split(' ');
Console.WriteLine("Incoming Chat from {0}", split[2]);
bool found = false;
if (Chats.Count != 0)
{
foreach (ChatWindow cw in Chats)
{
if (cw.User == split[2])
{
found = true;
cw.AddLine(cw.User, split[3]); // a function that adds a line to the current chat
}
}
}
if (!found)
{
ChatWindow temp = new ChatWindow(split[2], split[3]);
Chats.Add(temp); //this is a collection with T = ChatWindow
temp.Show();
}
}
}
If you're constructing NetworkSession from your UI Thread, you can snag a reference to the current Dispatcher that can manipulate the UI later.
NetworkSession.cs
private Dispatcher _dispatcher;
public NetworkSession()
{
_dispatcher = Dispatcher.CurrentDispatcher;
}
//any thread can call this method
public void DoStuff()
{
Action action = () =>
{
ChatWindow temp = new ChatWindow(split[2], split[3]);
Chats.Add(temp);
temp.Show();
};
_dispatcher.BeginInvoke(action);
}
The code below, which I took from here worked for me:
public static void StartChatWindow()
{
Thread thread = new Thread(() =>
{
ChatWindow chatWindow = new ChatWindow();
chatWindow.Chat(); // Do your stuff here, may pass some parameters
chatWindow.Closed += (sender2, e2) =>
// Close the message pump when the window closed
chatWindow.Dispatcher.InvokeShutdown();
// Run the message pump
System.Windows.Threading.Dispatcher.Run();
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
What you really need to do is construct the window/form on your main UI thread. You probably need to define a delegate that you can call from your network thread and that delegate should have a method attached that will call this.Dispatcher.BeginInvoke() -> inside which you will construct your window.
The this.Dispatcher.BeginInvoke() call is necessary to execute code on the UI thread, otherwise even with a delegate, code would be executed on the network thread.
Both the delegate and the method for creating a new chat window should probably be attached to the MainWindow...

BackgroundWorkerThread access in a thread

I use BackgroundWorker most of the time in the win form apps to show progress as I'm getting data. I was under impression that Work_completed is guaranteed to be executed on Main UI thread but it's not. If we create a thread and call the worker.RunWorkerAsync within it, it breaks if we try to update any gui control. Here is an example
private void StartButton_Click(object sender, EventArgs e)
{
Thread thread1 = new Thread(new ThreadStart(PerformWorkerTask));
_worker = new BackgroundWorker();
thread1.Start();
}
public void PerformWorkerTask()
{
_worker.DoWork += delegate
{
for (int i = 0; i < 10; i++)
{
Thread.Sleep(100);
}
};
_worker.RunWorkerCompleted += delegate
{
// this throws exception
MessageLabel.Text = "Completed";
};
_worker.RunWorkerAsync();
}
How can we make backgroundworker work in this case?
RunWorkerAsync does its thread-synchronization magic by getting the SynchronizationContext from the thread that it is called on. It then guarantees that the events will be executed on the correct thread according to the semantics of the SynchronizationContext it got. In the case of the WindowsFormsSynchronizationContext, which is what is automatically used if you're using WinForms, the events are synchronized by posting to the message queue of the thread that started the operation. Of course, this is all transparent to you until it breaks.
EDIT: You MUST call RunWorkerAsync from the UI thread for this to work. If you can't do it any other way, your best bet is to invoke the beginning of the operation on a control so that the worker is started on the UI thread:
private void RunWorker()
{
_worker = new BackgroundWorker();
_worker.DoWork += delegate
{
// do work
};
_worker.RunWorkerCompleted += delegate
{
MessageLabel.Text = "Completed";
};
_worker.RunWorkerAsync();
}
// ... some code that's executing on a non-UI thread ...
{
MessageLabel.Invoke(new Action(RunWorker));
}
From your example it's hard to see what good the Thread (thread1) is, but if you really do need this thread1 then I think your only option is to use MainForm.Invoke() to execute RunWorkerAsync() (or a small method around it) on the main thread.
Added: You can use something like this:
Action a = new Action(_worker.RunWorkerAsync);
this.Invoke(a);
It sounds like the issue is just that you want to make a change to a GUI component and you aren't actually sure if you're on the GUI thread. Dan posted a valid method of setting a GUI component property safely, but I find the following shortcut method the simplest:
MessageLabel.Invoke(
(MethodInvoker)delegate
{
MessageLabel.Text = "Hello World";
});
If there are any issues with this approach, I'd like to know about them!
In the code you have presented here, you're adding the delegates for the BackgroundWorker events in a separate thread from the UI thread.
Try adding the event handlers in the main UI thread, and you should be okay.
You could probably make your existing code work by doing:
this.Dispatcher.BeginInvoke(() => MessageLabel.Text = "Completed")
instead of
MessageLabel.Text = "Completed"
You're probably having cross-thread data access issues, so you have to ensure that you access properties of MessageLabel on your UI thread. This is one way to do that. Some of the other suggestions are valid too. The question to ask yourself is: why are you creating a thread that does nothing other than create a BackgroundWorker thread? If there's a reason, then fine, but from what you've shown here there's no reason you couldn't create and start the BackgroundWorker thread from your event handler, in which case there would be no cross-thread access issue because the RunWorkerCompleted event handler will call its delegates on the UI thread.
I believe BackgroundWorker is designed to automatically utilize a new thread. Therefore creating a new thread just to call RunWorkerAsync is redundant. You are creating a thread just to create yet another thread. What's probably happening is this:
You create a new thread from thread 1 (the GUI thread); call this thread 2.
From thread 2, you launch RunWorkerAsync which itself creates yet another thread; call this thread 3.
The code for RunWorkerCompleted runs on thread 2, which is the thread that called RunWorkerAsync.
Since thread 2 is not the same as the GUI thread (thread 1), you get an illegal cross-thread call exception.
(The below suggestion uses VB instead of C# since that's what I'm more familiar with; I'm guessing you can figure out how to write the appropriate C# code to do the same thing.)
Get rid of the extraneous new thread; just declare _worker WithEvents, add handlers to _worker.DoWork and _worker.RunWorkerCompleted, and then call _worker.RunWorkerAsync instead of defining a custom PerformWorkerTask function.
EDIT: To update GUI controls in a thread-safe manner, use code like the following (more or less copied from this article from MSDN):
delegate void SetTextCallback(System.Windows.Forms.Control c, string t);
private void SafeSetText(System.Windows.Forms.Control c, string t)
{
if (c.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SafeSetText);
d.Invoke(d, new object[] { c, t });
}
else
{
c.Text = t;
}
}
The best way to deal with these generic problems is to deal it once. Here I'm posting a small class that wraps the backgroupdworker thread and makes sure that the workcompleted always gets executed on the UI thread.
using System.Windows.Forms;
namespace UI.Windows.Forms.Utilities.DataManagment
{
public class DataLoader
{
private BackgroundWorker _worker;
private DoWorkEventHandler _workDelegate;
private RunWorkerCompletedEventHandler _workCompleted;
private ExceptionHandlerDelegate _exceptionHandler;
public static readonly Control ControlInvoker = new Control();
public DoWorkEventHandler WorkDelegate
{
get { return _workDelegate; }
set { _workDelegate = value; }
}
public RunWorkerCompletedEventHandler WorkCompleted
{
get { return _workCompleted; }
set { _workCompleted = value; }
}
public ExceptionHandlerDelegate ExceptionHandler
{
get { return _exceptionHandler; }
set { _exceptionHandler = value; }
}
public void Execute()
{
if (WorkDelegate == null)
{
throw new Exception(
"WorkDelegage is not assinged any method to execute. Use WorkDelegate Property to assing the method to execute");
}
if (WorkCompleted == null)
{
throw new Exception(
"WorkCompleted is not assinged any method to execute. Use WorkCompleted Property to assing the method to execute");
}
SetupWorkerThread();
_worker.RunWorkerAsync();
}
private void SetupWorkerThread()
{
_worker = new BackgroundWorker();
_worker.WorkerSupportsCancellation = true;
_worker.DoWork += WorkDelegate;
_worker.RunWorkerCompleted += worker_RunWorkerCompleted;
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if(e.Error !=null && ExceptionHandler != null)
{
ExceptionHandler(e.Error);
return;
}
ControlInvoker.Invoke(WorkCompleted, this, e);
}
}
}
And here is the usage. One thing to note is that it exposes a static property ControlInvoker that needs to be set only once (you should do it at the beginning of the app load)
Let's take the same example that I posted in question and re write it
DataLoader loader = new DataLoader();
loader.ControlInvoker.Parent = this; // needed to be set only once
private void StartButton_Click(object sender, EventArgs e)
{
Thread thread1 = new Thread(new ThreadStart(PerformWorkerTask));
_worker = new BackgroundWorker();
thread1.Start();
}
public void PerformWorkerTask()
{
loader.WorkDelegate = delegate {
// get any data you want
for (int i = 0; i < 10; i++)
{
Thread.Sleep(100);
}
};
loader.WorkCompleted = delegate
{
// access any control you want
MessageLabel.Text = "Completed";
};
loader.Execute();
}
Cheers

Categories