BackgroundWorker and instance variables - c#

One thing that's always confused me is how a BackgroundWorker seems to have thread-safe access to the instance variables of the surrounding class.
Given a basic class:
public class BackgroundProcessor
{
public List<int> Items { get; private set; }
public BackgroundProcessor(IEnumerable<int> items)
{
Items = new List<int>(items);
}
public void DoWork()
{
BackgroundWorker worker = new BackgroundWorker();
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerAsync();
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
var processor = new ProcessingClass();
processor.Process(this.Items); //Accessing the instance variable
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//Stuff goes here
}
}
Am I erroneous in my assumption the the call to processor.Process(this.Points); is a thread-safe call? How don't I get a cross-thread access violation?
I'm sure it's obvious, but it always has confused me.

It's not thread-safe, it just looks that way. You only get the cross-thread exception for GUI controls. There is a hard requirement that GUI controls only be accessed from the thread that created them. So the framework takes the time to check for calls from other threads. Note that this is actually orthogonal to synchronization issues (at least from our point of view, not from the point of view of the USER subsystem) as you could still use locks to prevent multiple threads from accessing a control at the same time and still get a cross-thread violation.
Since the member variable is not a GUI control, there is no check for cross-thread calls, nor is there a check for race conditions. You have to do that yourself with locking or some other mechanism. You will get no exception unless the collection classes get corrupted. I don't believe they are thread-safe, but I'm not sure what that ends up meaning, nor have I ever shared those kinds of variables between threads running at the same time, so I haven't actually had the problem. Suffice it to say, it's better to do the right thing than to hope that the collection classes magically work.

The background worker is a simple way of starting off a process on a different thread, it does not take care of thread safety for you.
If you are simply reading variables that have been changed by the background worker, this is fine.

Related

A function that only permits N concurrent threads

I have a Visual Studio 2008 C# .NET 3.5 project where a class listens for an event invocation from another class that is multithreaded. I need to ensure that my event only allows simultaneous access to a maximum of 10 threads. The 11th thread should block until one of the 10 finishes.
myobj.SomeEvent += OnSomeEvent;
private void OnSomeEvent(object sender, MyEventArgs args)
{
// allow up to 10 threads simultaneous access. Block the 11th thread.
using (SomeThreadLock lock = new SomeThreadLock(10))
{
DoUsefulThings(args.foo);
}
}
I do not have control over the other MyObj class, so I cannot implement a threadpool there.
What is the best way to implement this?
Thanks,
PaulH
You want the Semaphore class. It is, in short, a lock that only allows a specified number of callers through at any time.
Since you don't control the creation of threads, you do need to be careful about deadlock situations. Semaphores are not reentrancy-aware- if a given thread enters a semaphore more than once, it will take more than one slot. So if each of your caller's threads enters your semaphore more than once, there is the possibility of a deadlock.
Use a Semaphore for this. The constructor parameters are a little confusing to those just getting introduced to the class. The first parameter specifies the initial number of threads allowed through right now. The second parameter specifies the maximum number of threads allowed through at any given time.
myobj.SomeEvent += OnSomeEvent;
Semaphore semaphore = new Semaphore(10, 10);
private void OnSomeEvent(object sender, MyEventArgs args)
{
semaphore.WaitOne();
try
{
DoUsefulThings(args.foo);
}
finally
{
semaphore.Release();
}
}
It's customary to use a semaphore for this. Initialize it to 10 units. wait() for one unit before DoUsefulThings(), signal() one unit afterwards.

Why do I not get the "Cross-thread operation not valid" error

I use a BackgroundWorker and do this:
private void loadNewAsyncToolStripMenuItem_Click(object sender, EventArgs e)
{
this.Text = "RunWorkerAsync()";
backgroundWorkerLoading.RunWorkerAsync();
}
private void backgroundWorkerLoading_DoWork(object sender, DoWorkEventArgs e)
{
UnsafeThreadMethod("hello");
EvenUnsaferThreadMethod();
}
And now the two methods.
private void UnsafeThreadMethod(string text)
{
toolStripLabelRssFeedData.Text = text;
}
private void EvenUnsaferThreadMethod()
{
panelLoading.Visible = true;
}
I don't understand why UnsafeThreadMethod doesn't throw the following exception but EvenUnsaferThreadMethod does.
Cross-thread operation not valid: Control 'panelLoading' accessed from a thread other than the > thread it was created on.
According to the message it's because toolStripLabelRssFeedData was created on the same thread but it wasn't.
I thought that I can't call controls created by the main thread and have to use the ProgressChanged event. What's going on?
And I have a second question. What is the advantage of doing it like this when I can use ProgressChanged? What should I do?
private void EvenUnsaferThreadMethod()
{
if (panelLoading.InvokeRequired)
{
panelLoading.Invoke(new MethodInvoker(() => { EvenUnsaferThreadMethod(); }));
}
else
{
panelLoading.Visible = true;
}
}
To the first question:
the cross-thread exception is deliberately thrown in Debug mode. This means there is (conditional) code checking on InvokeRequired built into most of the GUI controls. Like the Panel.
Apparently the ToolstripLabel does not make this check. Since it does not derive from Control that could be because it is outside the scope of this safety net.
Since the standard disclaimer "Any instance members are not guaranteed to be thread safe" applies to the ToolstripLabel I would just go with the normal InvokeRequired logic when setting the Text.
For your first question, I am not entirely sure, but a review from online seems to show that sometimes this will not throw an exception, but it will not update the label. Is that the case here? Is your label being updated along with having no exception?
However, I can answer you second question right now. The ProgressChanged event is meant for exactly what it sounds like. It is supposed to be called to let the UI thread know the status of the backgroundworker so that it can update itself appropriately. The original calling thread (UI in this case) is the one that is used for the ProgressChanged, so when it updates it does not need to call Invoke. But, this should really only be done for showing the progress of a background worker.
Now, if it is not an update that you are trying to pass to the calling method, then I would suggest just passing your return data back through the RunWorkerCompleted event. This passes all of your final data back up to the original (UI) thread, so that it can update the UI without any need for an Invoke.
So, yes your call to Invoke will work, though. However, understanding what each of the other events are for can help you understand why to use one way over another. Maybe a ProgressChanged event fits better? It can also declutter your code from having unnecessary invokes.
Update to first q
I still cannot find anything about the toolstrip not needing the invoke. In fact I am finding the opposite using google searches like "toolstriplabel no cross thread exception" or "toolstriplabel invoke", etc. However, as henk mentioned, the toolstriplabel doesn't inherit from control so that might explain why no invoke is required. However, my suggestion is to assume that it will act like any other UI control and make sure it is updated on the UI thread to be safe. do not rely on quirks. Better safe than sorry, you never know if things like this might change, especially since it is logically a UI item to most..,
The advantage of your second choice is that it works :)
All UI elements are created on main UI thread and, what is more important from this question perspective, is that can be acessed only within that thread.
This is the reason why your first case fails and that is the reason your second case will work. Invoke()... will redirect required merhod call to the main UI thread.
Hope this helps.

Which of these functions is the more effective one?

When using the thread, 'invoke' is being used to avoid 'Cross Thread'(1)
but, sometimes 'timer object' is being used to avoid 'CrossThread' (2)
like this(for example)
public partial class Form1 : Form
{
private bool bCheckState = false;
public Form1()
{
InitializeComponent();
}
//Button Click
private void btnWork_Click(object sender, EventArgs e)
{
Thread m_Thread = new Thread(new ThreadStart(Work));
m_Thread.Start();
}
private void Work()
{
bCheckState = true;
// not use invoke
}
private void timer_Tick(object sender, EventArgs e)
{
if (bCheckState)
{
//tbxDisplay is winform's textBox control - printing data
tbxDisplay.Text = bCheckState.ToString();
bCheckState = false;
}
}
}
which one is more effective? 'between (1) and (2)'
Could it be a problem if we scatter the data processed within 'thread' after checking it in the 'timer event', without using 'invoke' or other methods? (We heard that to avoid 'Cross-Thread' when printing the data processed within 'thread', scattering the data in the 'timer event' with additional 'timer object' has been used quite often as it is neither beneficial nor harmful).
Just use a BackgroundWorker instance and handle the ReportProgress and/or RunWorkerCompleted events, which are already in the right thread.
As Ben Voigt suggested, a BackgroundWorker is probably what you should be using here, unless you have a good reason to want to use something else.
"Effective" is a rather vague means of comparison. Its not entirely clear what you're looking for in the two options you are considering.
BackgroundWorkers are simple and easy to understand, and they avoid the use of timers.
Invoke is more effective than a timer in the sense that there will be less of a delay between bCheckState becoming true and the text being updated. It will also be less CPU-intensive, since you won't have a timer polling at a set interval.
The Timer is more effective in the sense that the thread won't have to stop while invoking to update the text, but it is a bit inefficient because it is going to waste CPU time checking if the boolean has changed, and there could also be a delay of up to the timer interval length before the form changes.
As another alternative, BeginInvoke could be used to update the form without the use of a timer, and without the thread having to wait for the invoke to complete. However, if it raises an exception, your thread might not find out unless you also then call EndInvoke, which will also halt execution of the thread until the invoke is complete.
They all have their advantages and disadvantages, and you can't really call any particular one more "effective" in general.

Method doesn't return controlling

I have a grid on WPF form and another class, that has some events. From my wpf form i subscribe on those events and i want them to add some objects to my grid, but only that i have is "The calling thread cannot access this object because a different thread owns it." How can I avoid this proble and get same functionality?
This has been covered ad nauseam on StackOverflow and elsewhere. You need to use the Dispatcher to marshal your access back to the UI thread. For example:
private void OnSomeEvent(object sender, EventArgs e)
{
// this is being called on a thread other than the UI thread so marshal back to the UI thread
Dispatcher.BeginInvoke((ThreadStart)delegate
{
// now the grid can be accessed
grid.Whatever = foo;
});
}
This is a cross-threading issue. Look into delegate creation so you can safely invoke another thread to modify something that was created on the different thread. Here is a good MSDN article about how to make these thread-safe calls.
http://msdn.microsoft.com/en-us/library/ms171728(v=vs.80).aspx

Any solution to Illegal Cross Thread Operation exception?

When you data bind in C#, the thread that changes the data causes the control to change too. But if this thread is not the one on which the control was created, you'll get an Illegal Cross Thread Operation exception.
Is there anyway to prevent this?
You should be able to do something like:
if (control.InvokeRequired)
{
control.Invoke(delegateWithMyCode);
}
else
{
delegateWithMyCode();
}
InvokeRequired is a property on Controls to see if you are on the correct thread, then Invoke will invoke the delegate on the correct thread.
UPDATE: Actually, at my last job we did something like this:
private void SomeEventHandler(Object someParam)
{
if (this.InvokeRequired)
{
this.Invoke(new SomeEventHandlerDelegate(SomeEventHandler), someParam);
}
// Regular handling code
}
which removes the need for the else block and kind of tightens up the code.
As I don't have a test case to go from I can't guarantee this solution, but it seems to me that a scenario similar to the one used to update progress bars in different threads (use a delegate) would be suitable here.
public delegate void DataBindDelegate();
public DataBindDelegate BindData = new DataBindDelegate(DoDataBind);
public void DoDataBind()
{
DataBind();
}
If the data binding needs to be done by a particular thread, then let that thread do the work!
If the thread call is "illegal" (i.e. the DataBind call affects controls that were not created in the thread it is being called from) then you need to create a delegate so that even if the decision / preparation for the DataBind is not done in the control-creating thread, any resultant modification of them (i.e. DataBind()) will be.
You would call my code from the worker thread like so:
this.BindData.Invoke();
This would then cause the original thread to do the binding, which (presuming it is the thread that created the controls) should work.
In WPF and Silverlight the binding infrastructure takes care of the switching to the UI thread.

Categories

Resources