Thread safety in RunWorkerCompletedHandlers - c#

I'm having trouble figuring out the thread safety implications of using RunWorkerCompletedHandlers. I found this elsewhere on Stack Overflow:
If a BackgroundWorker is created on the UI thread, DoWork will run on a thread pool thread and RunWorkerCompleted will run on the UI thread.
If a BackgroundWorker is created on a background thread (ie not the UI thread) DoWork will still run on a thread pool thread and RunWorkerCompleted will also run on a thread pool thread.
Given the following class:
class TestingClass
{
private BackgroundWorker _bgWorker = new BackgroundWorker();
private int _counter = 0;
private readonly int _creatorID;
public TestingClass()
{
_creatorID = Environment.CurrentManagedThreadId;
_bgWorker.DoWork += DoAsyncWork;
_bgWorker.RunWorkerCompleted += CompleteAsyncWork;
_bgWorker.RunWorkerAsync();
}
public void IncrementCounter()
{
// We only allow the creator of this instance to call this function
// because instances of this class will not be shared with other threads.
Debug.Assert(_creatorID == Environment.CurrentManagedThreadId);
++_counter;
}
private void DoAsyncWork(object sender, DoWorkEventArgs e)
{
int i = 0;
while (i < 100000)
++i;
}
private void CompleteAsyncWork(object sender, RunWorkerCompletedEventArgs e)
{
// Apparently _creatorID == Environment.CurrentManagedThreadId isn't guaranteed here!
// Modification of member variable after the asynchronous part
// has been completed.
++_counter;
}
}
Since CompleteAsyncWork won't necessarily run on the thread that created the instance, I'm assuming that there's a chance the creating thread will be calling IncrementCounter while CompleteAsyncWork is being executed. Is it safe to modify member variables in a RunWorkerCompletedHandler in this case? If no, what would the right approach be?

If no, what would the right approach be?
The right approach is to only create a BGW on the main GUI thread. They're not much use in any other way.

Related

How to access the UI thread?

I have a Winform APP that does a simple task.
There is an event listener for a button that create a new thread:
ThreadStart work = (addToList);
Thread thread = new Thread(work);
thread.Start();
Now I need the second part of the calculation ot be done with the UI thread (so my instruction ask)
"
Note that you need to access the list box within the UI thread (hint: you can use Control.Invoke for WinForm
"
Any idea how to do so?
The Invoke method needs a delegate (reference to a function) and will schedule that on UI thread. Considering that all the elements on the form share the same thread as UI thread, you can use the Invoke method from either the form or any of its controls:
class MyForm
{
private void Button_Click(object sender, EventArgs e)
{
var thread = new Thread(new ThreadStart(FullCalculation));
thread.Start();
}
private void FullCalculation()
{
OffUIThreadCalculation();
this.Invoke(OnUIThreadCalculation); // Schedules OnUIThreadCalculation to run on the UI thread of `this`, aka the form
}
private void OffUIThreadCalculation()
{
// UI elements should not be used here
}
private void OnUIThreadCalculation()
{
// UI elements can be used here
}
}

C# Passing data to the original thread from Timer

This question is possibly a duplicate of How do you add a timer to a C# console application and few other similar questions but couldn't find the answer I'm looking for so asking again.
Question: How do you pass data from the Elapsed event of a Timer (System.Timers.Timer) to the thread that created the timer (that thread may not be the Main thread but another thread spawned by Main)?
I assume there could be some trivial way of achieving this eg. like the BackgroundWorker ProgressChanged event being called in the thread that created the worker, but couldn't find a way in MSDN documentation or SO. Most examples I've seen do some action in the timer thread (https://msdn.microsoft.com/en-us/library/system.timers.timer(v=vs.110).aspx) but don't pass anything to the original thread. Needless to say I'm pretty new to C#/.NET so a solution + pointers to references are appreciated.
Edit: I'd prefer not to use the Invoke()/InvokeRequired pattern (cf. How to use safe threading for a timer(Change timer properties from different thread) ) as this is not for a Forms application. I'm tempted to solve this by creating a BackgroundWorker that reports to the original thread at intervals (DoWork will be just a sleep() inside a loop) but thought .NET might have this already and hence the question.
Will you consider use a dispatcher? (although you need invoke some method too)
When some thread (maybe not the main thread) create the timer which you mentioned, you can create the dispatcher with the same thread too. After that, dispatcher.invoke() will let the original thread to do those task for you. See the MSDN for more information.
It seems to me that a simple locking mechanism is what you need:
private Object _sync = new Object();
void MyTimerFinished()
{
lock (_sync)
{
// Access shared data
...
}
}
void CodeExecutingInMainThread()
{
lock (_sync)
{
// Access shared data
...
}
}
Ok, so this is what I came up with (a solution with locks and Queues sounds a bit too complex for me - may be simpler but haven't tried)
public class ReportingTimer
{
public event EventHandler Elapsed;
private int _interval;
private BackgroundWorker _worker;
public ReportingTimer(int interval)
{
_interval = interval;
_worker = new BackgroundWorker();
_worker.WorkerReportsProgress = true;
_worker.WorkerSupportsCancellation = true;
_worker.DoWork += _worker_DoWork;
_worker.ProgressChanged += _worker_ProgressChanged;
}
public void Start()
{
if (!_worker.IsBusy)
{
_worker.RunWorkerAsync();
}
}
public void Stop()
{
if (_worker.IsBusy)
{
_worker.CancelAsync();
}
}
private void _worker_DoWork(object sender, DoWorkEventArgs e)
{
while (!_worker.CancellationPending)
{
Thread.Sleep(_interval);
_worker.ReportProgress(1);
}
if (_worker.CancellationPending)
{
e.Cancel = true;
}
}
private void _worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (!_worker.CancellationPending)
{
if (Elapsed != null)
{
Elapsed(this, new EventArgs());
}
}
}
}
Please critique.
Edit: This serves my purpose and the interface is similar to the Timer class and is actually what I wanted from the stock Timer.

Dead lock with backgroundWorker

I faced with one interesting moment when working with multithreading.
I have two threads. In main thread I create layout and add to it control,in second thread I create another control and add to the same layout. It works fine, but second thread works a bit longer then main. So main should wait for second thread.I use for this AutoResetEvent and got DeadLock. Below I describe code what I use:
private static AutoResetEvent resetEvent = new AutoResetEvent(false);
private BackgroundWorker backgroundAdvancedViewWorker = new BackgroundWorker();
private delegate void ShowViewDelegate();
public void Run()
{
MainGeneralReportForm mainForm = ObjectFactory.GetOrCreateView<IMainGeneralReportForm>();
backgroundSimpleViewWorker.RunWorkerAsync(_mainForm);
GeneralReportFormatView formatView =
ObjectFactory.ShowView<IGeneralReportFormatView>()
resetEvent.WaitOne();
DoSomething(advancedSearchView);
}
private void backgroundAdvancedViewWorker_DoWork(object sender, DoWorkEventArgs e)
{
MainGeneralReportForm mainForm = e.Argument as MainGeneralReportForm;
if (mainForm!= null && mainForm.InvokeRequired)
{
mainForm.BeginInvoke(new ShowViewDelegate(() =>
{
advancedSearchView =
ObjectFactory.ShowView<IGeneralReportAdvancedSearchView>();
resetEvent.Set();
}));
}
}
}
If main thread doesn't wait for second thread, the application throws NullReferenceException.
Is exist any solution or workaround of this problem?
You block main thread by resetEvent.WaitOne(); and at the same time trying to schedule work item back to main thread with BeginInvoke (which indeed can't run as main thread is waiting).
Not sure what right fix would be, but blocking on main thread is not really an option.
Maybe some "state" field on the form may be enough. Or maybe running DoSomething(advancedSearchView); from BeginInvoke callback (instead of resetEvent.Set();).
Note: if you are on 4.5 you can consider using async/await instead of manual threading.

Application is not responding, when i tried to updated UI from another thread

Execution Flow:
From main thread I invoked the new thread(Parallel thread), which is doing a long running process.
Parallel thread is updating the main thread UI.
I made my main thread to wait until parallel thread is complete.
I need a synchronization between two thread.
I need to use the result of parallel thread in main thread so I blocked main thread until parallel process complete.
Here is my code which is having issue,
please give suggestion to resolve the issue.
private readonly AutoResetEvent _resetEvent = new AutoResetEvent(false);
private event EventHandler Workcompleted;
private void button1_Click(object sender, EventArgs e)
{
Workcompleted += Completed;
Thread thr = new Thread(UpdateUI);
thr.Start("");
_resetEvent.WaitOne();
// Logical operation dependent on parallel process final result
}
private void Completed(object sender, EventArgs args)
{
_resetEvent.Set();
}
private void UpdateUI(object txt)
{
for (int i = 0; i < 10; i++)
{
if (label1.InvokeRequired)
{
label1.Invoke(new ParameterizedThreadStart(UpdateUI), i.ToString());
}
else
{
label1.Text = (string)txt;
Thread.Sleep(100);
}
}
if (Workcompleted != null)
Workcompleted(this, new EventArgs());
}
I made my main thread to wait until parallel thread is complete.
And there you blocked yourself. Why did you start a new thread in the first place? To keep the UI responsive. And now your blocked it anyway. Do not block it. I don't know what you want to do while the thread is running, probably changing control states and resetting them when the thread is done, but what you don't want is blocking your UI thread. Stop that and find another way to achieve whatever you want to achieve.
It seems you are looking for a way to report progress in the UI during the course of the parallel operation and wait for the final result (synchronize) to do something with it.
This could easily be accomplished using Async/Await, without having to run manual threads, synchronization constructs or thread marshaling (for UI invocation) and most importantly without blocking the UI thread.
Here is an example of how to run a parallel operation, report progress back to the UI, update UI continuously and finally do something with the result when it is available.
private async void button1_Click(object sender, EventArgs e)
{
var progress = new Progress<int>(ShowProgressInUi);
var result = await Task.Run(() => DoParallelWorkAsync(progress));
// Do something with final result
label1.Text = result;
}
private void ShowProgressInUi(int progress)
{
label1.Text = string.Format("Progress: {0} % done...", progress);
}
private static async Task<string> DoParallelWorkAsync(IProgress<int> progress)
{
// This work is done in a separate thread.
// In this case a background thread (from the thread pool),
// but could be run on a foreground thread if the work is lengthy.
for (var i = 1; i <= 10; i++)
{
// Simulate workload
await Task.Delay(100);
progress.Report(i * 10);
}
return "All done";
}
public delegate void Action();
private void UpdateUI(object txt)
{
this.BeginInvoke((Action)(() =>
{
label2.Text = (string)txt;
}));
}
By using this code, we don't need to wait for another thread...

progressBar separate thread

I have question about progressbar show value.
I have this main thread
private void button1_Click(object sender, EventArgs e)
{
progress prog = new progress();
progress.progressEvent += new progress.progressEventHandler(progressEvent);
for(int i=0;i<100;i++)
{
Thread.Sleep(100);
prog.incA();
}
}
void progressEvent(object sender)
{
if (progressBar1.InvokeRequired)
{
//Tady mi to caka az kym nedobehne cyklus for a pak zacne tohleto fungovat
progressBar1.Invoke(new ChangeProgressBarValue(ProgressStep));
}
else
{
ProgressStep();
}
}
public void ProgressStep()
{
progressBar1.PerformStep();
}
public class progress
{
private ThreadStart ts;
private Thread th;
private bool status = true;
public delegate void progressEventHandler(object sender);
public static event progressEventHandler progressEvent;
private int b,a = 0;
public progress()
{
ts=new ThreadStart(go);
th = new Thread(ts);
th.IsBackground = true;
th.Start();
}
public void incA()
{
a++;
if(a==100)
status = false;
}
private void go()
{
while (status)
{
if (a != b)
{
b = a;
if (progressEvent != null)
progressEvent(this);
}
}
th.Abort();
}
}
and my problem is IF start main thread and call IncA this method call event and in event is progressbar invoke
and this invoke waiting to end main thread FOR
why waiting?
thx
Your loop in the main thread is preventing "paint" events from happening. Since you are calling your progress bar's function from withing that thread, you will never see the updates.
You need to move the code to do the incrementing to another thread entirely.
Here is a sample of what you want to do using a Button, a BackgroundWorker, and a ProgressBar:
private void button1_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
for (int i = 1; i <= 100; i++)
{
backgroundWorker1.ReportProgress(i);
Thread.Sleep(100);
}
}
private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
this.progressBar1.Value = e.ProgressPercentage;
}
Hope this helps!
The progress bar control is a UI object, and is created on the UI thread. When you call Invoke or BeginInvoke to update it, you are asking the UI thread to do the updating.
However, the UI thread is busy - in your button CLick event handler, you have a loop which Sleep()s the thread and calls prog.IncA in a loop. So it never exits back to the main UI loop (which is what dispatches windows messages and updates the UI). Your progress bar is being updated internally, but it never gets a chance to redraw because the UI thread is "busy".
The "processing" code (that is looping and calling prog.IncA()) should not be running on the UI thread at all - you need to start it off in a separate thread and then exit your Click handler so that the UI can continue to update.
Note that this has a side effect - if your UI thread is running, then the user will be able to continue interacting with your program, and so they can click again on the button and kick off another background thread - so you have to be very careful to make sure that the user can't do anything "dangerous" in the UI while you are busy processing.
I suggest you look at some introduction-to-threading tutorials to get an idea of how to use BackgroundWorker or another mechanism for running code in a separate thread. Once you understand that, you can add a progress bar. (And note that although a progress bar sounds like the simplest thing to do, it is actually rather a difficult thing to do due to the need for the UI thread to continue running but not let the user do anything dangerous during your processing)

Categories

Resources