First of all, the code below seems to be working.
It extracts jpeg images from a continuous byte stream and displays them in a pictureBox as they arrive if the encapsulating packet checksum is correct.
The concern is intermittent GUI problems since the pictureBox is asynchronously updated by RxThread.
Is the method used here OK or might this crash while showing it to the customer?
public FormMain()
{
InitializeComponent();
var t1 = new Thread(RxThread) { IsBackground = true };
t1.Start();
}
private void RxThread()
{
while (true)
{
... // validate incoming stream
var payload = new Byte[payloadSize];
... // copy jpeg image from stream to payload
pictureBox.Image = new Bitmap(new MemoryStream(payload));
}
}
I think all access to UI controls should be done from UI thread. Modifying control from the thread that doesn't own the underlying handle may have undesirable effects. In the best case scenario the exception will be thrown, in the worst case everything may seem to be all right until some race condition happens (and you may spend lots of time trying to replicate it).
Use Invoke method, passing your delegate that will be executed on the UI thread.
Why you don't use Invoke to update the PictureBox?
Are you sure that even works at all? I don't see why it wouldn't raise a InvalidOperationException: (Cross-thread operation not valid) as the control is being updated from a thread other than the one which is was created on. You should update the UI via a delegate method that is invoked on the UI thread.
Related
I need to create window with loading gif when my main window is rendering. I have read some articles and make a decision that for this purposes i need to create new thread. I did it like in this article
As a result I have something like that:
LoadingDialog _loadingDlg;
Thread loadingThread;
public void ShowLoading()
{
loadingThread = new Thread(new ThreadStart(loadingThreadWork));
loadingThread.SetApartmentState(ApartmentState.STA);
loadingThread.Start();
}
private void loadingThreadWork()
{
_loadingDlg = new LoadingDialog();
_loadingDlg.Show();
System.Windows.Threading.Dispatcher.Run();
}
public void HideLoading()
{
_loadingDlg.Dispatcher.InvokeShutdown();
}
First time when I call ShowLoading() and then HideLoading() everything works like I want. But when I call ShowLoading() at the second time I get an exception at
_loadingDlg.Show();
with message The calling thread cannot access this object because a different thread owns it.
How can this be? _loadingDlg is created in the previous line, and in the same thread.
In the loadingThreadWork you're creating the control, before the first run it's a null, so in first time you succeed. However, you're creating the dialog in a different thread, which is marked as an owner for the control.
At the next time you're calling the loadingThreadWork, control isn't null, and ant change for it from a different thread (and it is a different thread, because you're creating it again) leads to the exception you've got.
As you're using WPF, you probably should switch from threads to async operations, which are much more readable, supportable and predictable than your current solution.
I have a UserControl with a TreeView control called mTreeView on it. I can get data updates from multiple different threads, and these cause the TreeView to be updated. To do this, I've devised the following pattern:
all data update event handlers must acquire a lock and then check for InvokeRequired; if so, do the work by calling Invoke. Here's the relevant code:
public partial class TreeViewControl : UserControl
{
object mLock = new object();
void LockAndInvoke(Control c, Action a)
{
lock (mLock)
{
if (c.InvokeRequired)
{
c.Invoke(a);
}
else
{
a();
}
}
}
public void DataChanged(object sender, NewDataEventArgs e)
{
LockAndInvoke(mTreeView, () =>
{
// get the data
mTreeView.BeginUpdate();
// perform update
mTreeView.EndUpdate();
});
}
}
My problem is, sometimes, upon startup, I will get an InvalidOperationException on mTreeView.BeginUpdate(), saying mTreeView is being updated from a thread different than the one it was created. I go back in the call stack to my LockAndInvoke, and lo and behold, c.InvokeRequired is true but the else branch was taken! It's as if InvokeRequired had been set to true on a different thread after the else branch was taken.
Is there anything wrong with my approach, and what can I do to prevent this?
EDIT: my colleague tells me that the problem is that InvokeRequired is false until the control is created, so this is why it happens on startup. He's not sure what to do about it though. Any ideas?
It is a standard threading race. You are starting the thread too soon, before the TreeView is created. So your code sees InvokeRequired as false and fails when a split second later the native control gets created. Fix this by only starting the thread when the form's Load event fires, the first event that guarantees that all the control handles are valid.
Some mis-conceptions in the code btw. Using lock is unnecessary, both InvokeRequired and Begin/Invoke are thread-safe. And InvokeRequired is an anti-pattern. You almost always know that the method is going to be called by a worker thread. So use InvokeRequired only to throw an exception when it is false. Which would have allowed diagnosing this problem early.
When you marshal back to the UI thread, it's one thread--it can do only one thing at at time. You don't need any locks when you call Invoke.
The problem with Invoke is that it blocks the calling thread. That calling thread usually doesn't care about what get's completed on the UI thread. In that case I recommend using BeginInvoke to marshal the action back to the UI thread asynchronously. There are circumstances where the background thread can be blocked on Invoke while the UI thread can be waiting for the background thread to complete something and you end up with a deadlock: For example:
private bool b;
public void EventHandler(object sender, EventArgs e)
{
while(b) Thread.Sleep(1); // give up time to any other waiting threads
if(InvokeRequired)
{
b = true;
Invoke((MethodInvoker)(()=>EventHandler(sender, e)), null);
b = false;
}
}
... the above will deadlock on the while loop while because Invoke won't return until the call to EventHandler returns and EventHandler won't return until b is false...
Note my use of a bool to stop certain sections of code from running. This is very similar to lock. So, yes, you can end up having a deadlock by using lock.
Simply do this:
public void DataChanged(object sender, NewDataEventArgs e)
{
if(InvokeRequired)
{
BeginInvoke((MethodInvoker)(()=>DataChanged(sender, e)), null);
return;
}
// get the data
mTreeView.BeginUpdate();
// perform update
mTreeView.EndUpdate();
}
This simply re-invokes the DataChanged method asynchronously on the UI thread.
The pattern as you have shown it above looks 100% fine to me (albeit with some extra unnecessary locking, however I can't see how this would cause the problem you have described).
As David W points out, the only difference between what you are doing and this extension method is that you directly access mTreeView on the UI thread instead of passing it in as an argument to your action, however this will only make a difference if the value of mTreeView changes, and in any case you would have to try fairly hard to get this to cause the problem you have described.
Which means that the problem must be something else.
The only thing that I can think of is that you may have created mTreeView on a thread other than the UI thread - if this is the case then accessing the tree view will be 100% safe, however if you try and add that tree view to a form which was created on a different thread then it will go bang with an exception similar to the one that you describe.
I am currently trying to update a chart which is on my form to the background worker using:
bwCharter.RunWorkerAsync(chart1);
Which runs:
private void bcCharter_DoWork(object sender, DoWorkEventArgs e)
{
System.Windows.Forms.DataVisualization.Charting.Chart chart = null;
// Convert e.Argument to chart
//..
// Converted..
chart.Series.Clear();
e.Result=chart;
setChart(c.chart);
}
private void setChart(System.Windows.Forms.DataVisualization.Charting.Chart arg)
{
if (chart1.InvokeRequired)
{
chart1.Invoke(new MethodInvoker(delegate { setChart(arg); }));
return;
}
chart1 = arg;
}
However, at the point of clearing the series, an exception is thrown.
Basically, I want to do a whole lot more processing after clearing the series, which slows the GUI down completely - so wanted this in another thread.
I thought that by passing it as an argument, I should be safe, but apparently not!
Interestingly, the chart is on a tab page. I can run this over and over if the tabpage is in the background, but if I run this, look at the chart, hide it again, and re-run, it throws the exception. Obviously, it throws if the chart is in the foreground as well.
Can anyone suggest what I can do differently?
Thanks!
EDIT:
I know that this can be done in the form thread, as when I assign it back again. However the whole point of using a background worker is to avoid grinding the whole program to a halt. As I said, there is a lot more processing than just this one command.
I assumed that passing it as an argument would allow me to access it in that thread unhindered, but is there a chance that this passed chart still points back to the original chart in some way? If so, how can this be overcome?
I want to block the GUI thread as little as possible - so there seems no point in just invoking every command.
If you want to clear it first, then do a lot of asynchronous work before you redisplay it, why don't you call chart.Series.Clear(); before you invoke the BackgroundWorker? In that case it gets cleared on the main UI thread, then you perform som async work before you again set the chart from the UI thread.
Also, when using a BackgroundWorker, I would use the inbuilt ReportProgress and WorkerCompleted events to avoid the manual cross-thread invoking. That's part of the reason of using the BackgroundWorker in the first place to get this kind of functionality for "free". So setting the chart should be done in the WorkerCompleted to simplify your code (even if that is not the source of the problem in this case).
Check for Invoke Required in bcCharter_DoWork, if yes put the Clear method call in a delegate too.
if (InvokeRequired)
{
Invoke(new MethodInvoker(delegate
{
chart.Series.Clear();
e.Result=chart;
}));
return;
}
I agree with the analysis in the previous posts : you ask a thread to access to a resource of another thread.
Like you used a BackgroundWorker I suggest you to use the Dispatcher :
private void bcCharter_DoWork(object sender, DoWorkEventArgs e)
{
Chart chart = null;
Dispatcher.Invoke(DispatcherPriority.Normal,
new Action(() =>
{
chart.Series.Clear();
}));
}
The problem you are encountering is that you cannot access UI elements on threads other than the one they were created on. However, in your case you can simply clear the chart before calling the background worker.
You can manually marshal UI element access to the correct thread from another thread using Control.Invoke.
I am using a background thread to initialize an instrument over USB. The UI hangs when I try to open the device. I would expect the background thread to pause when calling Open on the device, but not the UI thread. I am testing this with no UI interaction from the background thread. I don't know how to debug the problem, and it's too broad a question, but perhaps someone has seen something like this before. There is nothing wrong with the ActiveX interop as far as I know, the device works correctly. This is the general approach:
using System;
using FancyVoltmeterLibrary;
namespace SOQuestion
{
public class MeterClass
{
private FancyVoltmeter meter;
private Thread meterThread;
public MeterClass()
{
// Create instance of ActiveX/COM object.
meter = new FancyVoltmeter();
meterThread = new Thread(UpdateMeter);
meterThread.Name = "Meter Thread";
meterThread.Priority = ThreadPriority.Normal;
meterThread.IsBackground = true;
meterThread.Start();
}
private void UpdateMeter()
{
while(true)
{
Thread.Sleep(1000);
if(!meter.IsOpen())
{
// Meter may be powered off here.
// The call to Open takes about 1 second.
// UI hangs during the call???
meter.Open();
}
// code to read meter goes here.
}
}
}
}
Edit: Perhaps unclear what I meant. By 'hang' I should say 'freezes momentarily'.
Does meter require running in an STA? Is the call to Open() actually being marshalled back to the UI thread for this reason?
You can verify this is true by looking at the callstack of the hung UI thread in the debugger.
How long time does the instantiation of the FancyVoltmeter take? Could it be that it is not the Open method that causes the UI freeze, but creating the COM object (which is done on the UI thread)?
If that turns out to be the case, moving the creation of this object to happen on the new, separate worker thread should take care of the problem.
Edit: I saw now that you already found this out in your comment to Michael...
I would suggest you wrap the call to meter.open() in a separate method, and call that method from within the updateMeter() method using Invoke() or BeginInvoke() construct on the form or parent control. Doing this will marshal the action back on to the UI thread and should execute gracefully. I hope this helps.
Consider using a BackgroundWorker for this task.
Lets say I have a component called Tasking (that I cannot modify) which exposes a method “DoTask” that does some possibly lengthy calculations and returns the result in via an event TaskCompleted. Normally this is called in a windows form that the user closes after she gets the results.
In my particular scenario I need to associate some data (a database record) with the data returned in TaskCompleted and use that to update the database record.
I’ve investigated the use of AutoResetEvent to notify when the event is handled. The problem with that is AutoResetEvent.WaitOne() will block and the event handler will never get called. Normally AutoResetEvents is called be a separate thread, so I guess that means that the event handler is on the same thread as the method that calls.
Essentially I want to turn an asynchronous call, where the results are returned via an event, into a synchronous call (ie call DoSyncTask from another class) by blocking until the event is handled and the results placed in a location accessible to both the event handler and the method that called the method that started the async call.
public class SyncTask
{
TaskCompletedEventArgs data;
AutoResetEvent taskDone;
public SyncTask()
{
taskDone = new AutoResetEvent(false);
}
public string DoSyncTask(int latitude, int longitude)
{
Task t = new Task();
t.Completed = new TaskCompletedEventHandler(TaskCompleted);
t.DoTask(latitude, longitude);
taskDone.WaitOne(); // but something more like Application.DoEvents(); in WinForms.
taskDone.Reset();
return data.Street;
}
private void TaskCompleted(object sender, TaskCompletedEventArgs e)
{
data = e;
taskDone.Set(); //or some other mechanism to signal to DoSyncTask that the work is complete.
}
}
In a Windows App the following works correctly.
public class SyncTask
{
TaskCompletedEventArgs data;
public SyncTask()
{
taskDone = new AutoResetEvent(false);
}
public string DoSyncTask(int latitude, int longitude)
{
Task t = new Task();
t.Completed = new TaskCompletedEventHandler(TaskCompleted);
t.DoTask(latitude, longitude);
while (data == null) Application.DoEvents();
return data.Street;
}
private void TaskCompleted(object sender, TaskCompletedEventArgs e)
{
data = e;
}
}
I just need to replicate that behaviour in a window service, where Application.Run isn’t called and the ApplicationContext object isn’t available.
I've had some trouble lately with making asynchronous calls and events at threads and returning them to the main thread.
I used SynchronizationContext to keep track of things. The (pseudo)code below shows what is working for me at the moment.
SynchronizationContext context;
void start()
{
//First store the current context
//to call back to it later
context = SynchronizationContext.Current;
//Start a thread and make it call
//the async method, for example:
Proxy.BeginCodeLookup(aVariable,
new AsyncCallback(LookupResult),
AsyncState);
//Now continue with what you were doing
//and let the lookup finish
}
void LookupResult(IAsyncResult result)
{
//when the async function is finished
//this method is called. It's on
//the same thread as the the caller,
//BeginCodeLookup in this case.
result.AsyncWaitHandle.WaitOne();
var LookupResult= Proxy.EndCodeLookup(result);
//The SynchronizationContext.Send method
//performs a callback to the thread of the
//context, in this case the main thread
context.Send(new SendOrPostCallback(OnLookupCompleted),
result.AsyncState);
}
void OnLookupCompleted(object state)
{
//now this code will be executed on the
//main thread.
}
I hope this helps, as it fixed the problem for me.
Maybe you could get DoSyncTask to start a timer object that checks for the value of your data variable at some appropriate interval. Once data has a value, you could then have another event fire to tell you that data now has a value (and shut the timer off of course).
Pretty ugly hack, but it could work... in theory.
Sorry, that's the best I can come up with half asleep. Time for bed...
I worked out a solution to the async to sync problem, at least using all .NET classes.
Link
It still doesn't work with COM. I suspect because of STA threading. The Event raised by the .NET component that hosts the COM OCX is never handled by my worker thread, so I get a deadlock on WaitOne().
someone else may appreciate the solution though :)
If Task is a WinForms component, it might be very aware of threading issues and Invoke the event handler on the main thread -- which seems to be what you're seeing.
So, it might be that it relies on a message pump happening or something. Application.Run has overloads that are for non-GUI apps. You might consider getting a thread to startup and pump to see if that fixes the issue.
I'd also recommend using Reflector to get a look at the source code of the component to figure out what it's doing.
You've almost got it. You need the DoTask method to run on a different thread so the WaitOne call won't prevent work from being done. Something like this:
Action<int, int> doTaskAction = t.DoTask;
doTaskAction.BeginInvoke(latitude, longitude, cb => doTaskAction.EndInvoke(cb), null);
taskDone.WaitOne();
My comment on Scott W's answer seems a little cryptic after I re-read it. So let me be more explicit:
while( !done )
{
taskDone.WaitOne( 200 );
Application.DoEvents();
}
The WaitOne( 200 ) will cause it to return control to your UI thread 5 times per second (you can adjust this as you wish). The DoEvents() call will flush the windows event queue (the one that handles all windows event handling like painting, etc.). Add two members to your class (one bool flag "done" in this example, and one return data "street" in your example).
That is the simplest way to get what you want done. (I have very similar code in an app of my own, so I know it works)
Your code is almost right... I just changed
t.DoTask(latitude, longitude);
for
new Thread(() => t.DoTask(latitude, longitude)).Start();
TaskCompleted will be executed in the same thread as DoTask does. This should work.