I have a scenario where I have a main thread which uses a whole bunch of other threads from the threadpool that do some work.
In the main thread I am using an object which is not thread safe (3rd party component, so it's not feasible to change this). The threadpool threads need to invoke methods on this non-thread-safe object. In the main thread I have an object representing the thread on which the 3rd party component is declared:
private ThirdPartyComponent third_party_component;
private Thread mainThread;
In the initialization method on the main thread, I save a reference to the "safe" thread for accessing the 3rd party component:
mainThread = Thread.CurrentThread;
What I am trying to do is create some method which will "dispatch" the invocation of the 3rd party component to the correct thread, something like this:
private void DoTheWork()
{
if(Thread.CurrentThread != mainThread)
{
mainThread.Invoke( () => { third_party_component.DoItThreadSafe(); } );
}
}
I have regularly used this pattern for updating UI code on the main thread using Control.Invoke, but the Thread object which I have saved (mainThread) does not have an Invoke method.
Is there something special about the UI thread that allows this to take place? Or am I missing something on the Thread object? What is the best way to get DoTheWork() to run on the main thread?
(Edit: FWIW in this application mainThread will be the main Winforms GUI thread, but I am hoping to find a solution which works on any thread and does not rely on the main thread being the GUI thread.)
Normally when talking about non-threadsafe objects it simply means it cannot be called by multiple threads concurrently. If so it should be safe to simply lock the non-threadsafe object and call it from whatever thread you are using.
It is possible to write objects that can only be called by the thread that created the object thread. If so perhaps something like this could work:
public class TaskManager<T>
{
private readonly Func<T> constructor;
private BlockingCollection<Action<T>> queue = new BlockingCollection<Action<T>>(new ConcurrentQueue<Action<T>>());
public TaskManager(Func<T> constructor)
{
this.constructor = constructor;
var thread = new Thread(ThreadMain);
thread.Start();
}
private void ThreadMain()
{
var obj = constructor();
foreach(var action in queue.GetConsumingEnumerable())
{
action(obj);
}
}
public void ScheduleWork(Action<T> work) => queue.Add(work);
public void CompleteAdding() => queue.CompleteAdding();
}
Disclaimer: Not tested, no error handling, no handling of disposable objects etc.
I have a multi-threaded application where each thread has the ability to log pending GUI updates by utilizing a shared (and thread safe) BlockingCollection that contains guiUpdateObjects.
Each guiUpdateObject contains information on which control to update and the content to be displayed. I'd like to have my Form consume any items that exist on that BlockingCollection and update the various controls accordingly.
This set up worked well for me previously in the Java version of this application where after spawning threads and doing initialization tasks, the main thread checked for items on a timed loop.
I suppose I could do the same in C# with a timer event but given all the native event handling in Windows Forms, I'm wondering if there's a better way. Perhaps, with a custom event? Would appreciate any criticisms on my current approach and/or suggestions on how best to implement this in C#.
Update based on Hans suggestion:
After reading up on Control.BeginInvoke(), I understand that this will allow me to PostMessage to the application message queue. This is similar to my utilization of BlockingCollection in that it's thread safe and immediately returns without waiting for the message to be processed.
However, utilizing BeginInvoke requires using delegates and after reading up on them, I'm still a bit confused on proper implementation. Do I declare the delegate in my Form class or in the 'worker' class that will be generating content for gui updates? If I declare in my Form class, the method won't be visible to my worker class unless I reference the Form object. Alternatively, if I declare in the worker class, how will the Form class make the association between the delegate method and the actual method? Here's some code highlighting my question:
public partial class GUI : Form
{
public GUI()
{
InitializeComponent();
Thread workerThread = new Thread(new ThreadStart(new Worker().DoWork));
workerThread.Start();
}
private delegate void AppendSysLogDelegate(string logEntry);
private void AppendSysLog(string logEntry)
{
if (this.InvokeRequired)
{
this.BeginInvoke(new AppendSysLogDelegate(AppendSysLog), new object[] { logEntry });
return;
}
systemLogger.AppendText(logEntry);
}
}
public class Worker
{
public void DoWork()
{
//what goes here to call AppendSysLog("Test log entry");
}
}
Check this question and make a note of the excellent answer:
Is there anything like asynchronous BlockingCollection<T>?
Now that you have been armed with an equivalent of blockingCollection.TakeAsync(), you can await its result on a UI thread, for example:
async void btnTest_Click(object s, EventArgs e)
{
// don't forget to add exception handling
while(true)
{
var result = await blockingCollection.TakeAsync();
this.textBox.AppendText(result.ToString());
}
}
Consider two classes; Producer and Consumer (the same as classical pattern, each with their own threads). Is it possible for Producer to have an Event which Consumer can register to and when the producer triggers the event, the consumer's event handler is run in its own thread? Here are my assumptions:
Consumer does not know if the Producer's event is triggered
within his own thread or another.
Neither Producer nor Consumer are descendants of Control so they don't have
BeginInvoke method inherited.
PS. I'm not trying to implement Producer - Consumer pattern. These are two simple classes which I'm trying to refactor the producer so it incorporates threads.
[UPDATE]
To further expand my problem, I'm trying to wrap a hardware driver to be worked with in the simplest way possible. For instance my wrapper will have a StateChanged event which the main application will register to so it will be notified when hardware is disconnected. As the actual driver has no means other than polling to check its presence , I will need to start a thread to check it periodically. Once it is not available anymore I will trigger the event which needs to be executed in the same thread as it was added. I know this is a classical Producer-Consumer pattern but since I'm trying to simplify using my driver-wrapper, I don't want the user code to implement consumer.
[UPDATE]
Due to some comments suggesting that there's no solution to this problem, I would like to add few lines which might change their minds. Considering the BeginInvoke can do what I want, so it shouldn't be impossible (at least in theory). Implementing my own BeginInvoke and calling it within the Producer is one way to look at it. It's just that I don't know how BeginInvoke does it!
You want to do inter thread communication. Yes it is possible.
Use System.Windows.Threading.Dispatcher
http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.aspx
The Dispatcher maintains a prioritized queue of work items for a specific thread.
When a Dispatcher is created on a thread, it becomes the only Dispatcher that can be associated with the thread, even if the Dispatcher is shut down.
If you attempt to get the CurrentDispatcher for the current thread and a Dispatcher is not associated with the thread, a Dispatcher will be created. A Dispatcher is also created when you create a DispatcherObject. If you create a Dispatcher on a background thread, be sure to shut down the dispatcher before exiting the thread.
Yes there is a way to do this. It relies on using the SynchronizationContext class (docs). The sync context abstracts the operations of sending messages from one thread to another via the methods Send (synchronous for the calling thread) and Post(async for the calling thread).
Let's take a slightly simpler situation where you only want the capture one sync context, the context of the "creator" thread. You would do something like this:
using System.Threading;
class HardwareEvents
{
private SynchronizationContext context;
private Timer timer;
public HardwareEvents()
{
context = SynchronizationContext.Current ?? new SynchronizationContext();
timer = new Timer(TimerMethod, null, 0, 1000); // start immediately, 1 sec interval.
}
private void TimerMethod(object state)
{
bool hardwareStateChanged = GetHardwareState();
if (hardwareStateChanged)
context.Post(s => StateChanged(this, EventArgs.Empty), null);
}
public event EventHandler StateChanged;
private bool GetHardwareState()
{
// do something to get the state here.
return true;
}
}
Now, the creating thread's sync context will be used when events are invoked. If the creating thread was a UI thread it will have a sync context supplied by the framework. If there is no sync context, then the default implementation is used, which invokes on the thread pool. SynchronizationContext is a class that you can subclass if you want to provide a custom way to send a message from the producer to the consumer thread. Just override Post and Send to send said message.
If you wanted every event subscriber to get called back on their own thread, you would have to capture the sync context in the add method. You then hold on to pairs of sync contexts and delegates. Then when raising the event, you would loop through the sync context / delegate pairs and Post each one in turn.
There are several other ways you could improve this. For example, you may want to suspend polling the hardware if there no subscribers to the event. Or you might want to back off your polling frequency if the hardware does not respond.
First, please note that in .NET / the Base Class Library, it is usually the event subscriber's obligation to ensure that its callback code is executing on the correct thread. That makes it easy for the event producer: it may just trigger its event without having to care about any thread affinities of its various subscribers.
Here's a complete example step-by-step of a possible implementation.
Let's start with something simple: The Producer class and its event, Event. My example won't include how and when this event gets triggered:
class Producer
{
public event EventHandler Event; // raised e.g. with `Event(this, EventArgs.Empty);`
}
Next, we want to be able to subscribe our Consumer instances to this event and be called back on a specific thread (I'll call this kind of thread a "worker thread"):
class Consumer
{
public void SubscribeToEventOf(Producer producer, WorkerThread targetWorkerThread) {…}
}
How do we implement this?
First, we need the means to "send" code to a specific worker thread. Since there is no way to force a thread to execute a particular method whenever you want it to, you must arrange for a worker thread to explicitly wait for work items. One way to do this is via a work item queue. Here's a possible implementation for WorkerThread:
sealed class WorkerThread
{
public WorkerThread()
{
this.workItems = new Queue<Action>();
this.workItemAvailable = new AutoResetEvent(initialState: false);
new Thread(ProcessWorkItems) { IsBackground = true }.Start();
}
readonly Queue<Action> workItems;
readonly AutoResetEvent workItemAvailable;
public void QueueWorkItem(Action workItem)
{
lock (workItems) // this is not extensively tested btw.
{
workItems.Enqueue(workItem);
}
workItemAvailable.Set();
}
void ProcessWorkItems()
{
for (;;)
{
workItemAvailable.WaitOne();
Action workItem;
lock (workItems) // dito, not extensively tested.
{
workItem = workItems.Dequeue();
if (workItems.Count > 0) workItemAvailable.Set();
}
workItem.Invoke();
}
}
}
This class basically starts a thread, and puts it in an infinite loop that falls asleep (WaitOne) until an item arrives in its queue (workItems). Once that happens, the item — an Action — is dequeued and invoked. Then the thread goes to sleep again (WaitOne)) until another item is available in the queue.
Actions are put in the queue via the QueueWorkItem method. So essentially we can now send code to be executed to a specific WorkerThread instance by calling that method. We're now ready to implement Customer.SubscribeToEventOf:
class Consumer
{
public void SubscribeToEventOf(Producer producer, WorkerThread targetWorkerThread)
{
producer.Event += delegate(object sender, EventArgs e)
{
targetWorkerThread.QueueWorkItem(() => OnEvent(sender, e));
};
}
protected virtual void OnEvent(object sender, EventArgs e)
{
// this code is executed on the worker thread(s) passed to `Subscribe…`.
}
}
Voilà!
P.S. (not discussed in detail): As an add-on, you could package the method of sending code to WorkerThread using a standard .NET mechanism called a SynchronizationContext:
sealed class WorkerThreadSynchronizationContext : SynchronizationContext
{
public WorkerThreadSynchronizationContext(WorkerThread workerThread)
{
this.workerThread = workerThread;
}
private readonly WorkerThread workerThread;
public override void Post(SendOrPostCallback d, object state)
{
workerThread.QueueWorkItem(() => d(state));
}
// other overrides for `Send` etc. omitted
}
And at the beginning of WorkerThread.ProcessWorkItems, you'd set the synchronization context for that particular thread as follows:
SynchronizationContext.SetSynchronizationContext(
new WorkerThreadSynchronizationContext(this));
I posted earlier that I've been there, and that there is no nice solution.
However, I just stumbled upon something I have done in another context before: you could instantiate a timer (that is, Windows.Forms.Timer) when you create your wrapper object. This timer will post all Tick events to the ui thread.
Now if you're device polling logic is non-blocking and fast, you could implement it directly inside the timer Tick event, and raise your custom event there.
Otherwise, you could continue to do the polling logic inside a thread, and instead of firing the event inside the thread, you just flip some boolean variable which gets read by the timer every 10 ms, who then fires the event.
Note that this solution still requires that the object is created from the GUI thread, but at least the user of the object will not have to worry about Invoke.
It is possible. One typical approach is to use the BlockingCollection class. This data structure works like a normal queue except that the dequeue operation blocks the calling thread if the queue is empty. The produce will queue items by calling Add and the consumer will dequeue them by calling Take. The consumer typically runs it's own dedicated thread spinning an infinite loop waiting for items to appear in the queue. This is, more or less, how the message loop on the UI thread operates and is the basis for getting the Invoke and BeginInvoke operations to accomplish the marshaling behavior.
public class Consumer
{
private BlockingCollection<Action> queue = new BlockingCollection<Action>();
public Consumer()
{
var thread = new Thread(
() =>
{
while (true)
{
Action method = queue.Take();
method();
}
});
thread.Start();
}
public void BeginInvoke(Action method)
{
queue.Add(item);
}
}
Suppose you are invoking methods asynchronously onto the UI thread.
With
UIDispatcher.BeginInvoke( new Action(_insert), DispatcherPriority.Normal, new object[] { } )
you are doing the invocation. From now the runtime environment decides when to execute the method whereas the program continues its 'normal' path of execution.
I am now wondering whether there are any mechanisms to synchronize these asynchronously executed methods when they are returning ? It seems that there are pretty much the same issues as when using multiple threads.
But is a returning method that has been invoked asynchronously before considered to be a thread ? It don't seem so because usual synchronizing efforts like
lock (someObject) { //... }
or using dedicated locks seem not to work.
Appendix:
My actual situation where this issue appears is as follows:
The asynchronously invoked method calls as its last statement a returnmethod of a static class. Inside this return method a commonly used resource (a List) has to be synchronized. Consider the following (overview-like) code-snipped to exemplify:
// A simple method that gets invoked asynchronously
public void _insert () {
// do some code
StaticClass.Returned();
}
public static StaticClass {
//...
public static void Returned () {
// use a shared resource !
}
}
Either use the .NET's asynchronous pattern, a BackgroundWorker, or a ManualResetEvent
http://msdn.microsoft.com/en-us/library/ms228969.aspx
Within a class library I'm writing I have a method allowing the library to go and do some stuff on a different thread which does something like:
public void DoStuffAsync(AP p)
{
this.Running = true;
this.Cancel = false;
ParameterizedThreadStart threadStart = new ParameterizedThreadStart(DoStuff);
Thread procThread = new Thread(threadStart);
procThread.Start(p);
}
I also have a number of events declared on the interface that the developer can hook into, such as StatusUpdate and ProgressUpdate. I'm currently writing a little test app (in WPF presently although I expect the same behaviour in WinForms) that calls DoStuffAsync() and then updates a progress bar and label.
Unfortunately 1st pass I got an error, the usual thread not being the one which owns the controls. What I'd like to do is remove the need for the user to call Invoke() within the UI side, and for them to simply subscribe to the events and have them work.
So the question, is there a way I can do this is my code when dealing with the event handlers? Currently trigger like so:
public void UpdateProgress(object sender, ProgressEventArgs e)
{
if (handler != null)
{
handler(sender, e);
}
}
Use the AsyncOperationManager instead.
It will do the invoke for you.
(internally it uses the SynchronizationContext as nobugz describes)
You will need a reference to the client's Dispatcher object so you can call Dispatcher.Invoke or Dispatcher.BeginInvoke to marshal the call to the client's UI thread. Do so by letting the client give you the reference you'll need either through the constructor or with a property.
Another way to do it is to store a reference to SynchronizationContext.Current in your class constructor. Use its Send or Post method. That however requires the client to have WPF initialized properly (Application.Run must have been called) and construct your class object from its UI thread.