I am using threading in my code , thread are created using function:
private void InitializeBackgoundWorkers()
{
for (int f = 0; f < maxThreads; f++)
{
listBox1.Items.Insert(0, "Starting Thread : " + (f + 1));
threadArray[f] = new BackgroundWorker();
threadArray[f].DoWork +=
new DoWorkEventHandler(backgroundWorkerFiles_DoWork);
threadArray[f].RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(backgroundWorkerFiles_RunWorkerCompleted);
threadArray[f].ProgressChanged +=
new ProgressChangedEventHandler(backgroundWorkerFiles_ProgressChanged);
threadArray[f].WorkerReportsProgress = true;
threadArray[f].WorkerSupportsCancellation = true;
}
}
And the doevent is something like :
private void backgroundWorkerFiles_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
int flag = 0;
while (rowCounter < allPostingRows.Tables[0].Rows.Count && flag == 0)
{
for (int i = 0; i < maxThreads; i++)
{
if (threadArray[i].CancellationPending == true)
{
flag = 1;
threadArray[i].CancelAsync();
worker.ReportProgress(0, "Thread Paused:");
}
}
if (flag == 0)
{
//perform work here
}
}
}
And on button i try to cancel the threads using:
for (int i = 0; i < maxThreads; i++)
{
threadArray[i].CancelAsync();
}
Am i cancelling the thread correctly? As when they get canceled i see the line in listbox saying thread cancelled so it does go to the cancellation code but after some time it restarts
Thank you
I don't think you really understand BackgroundWorker. The DoWork event handler is supposed to be a handler for one unit of work. DoWork is called with one thread. It doesn't make sense to call CancelAsync from within a DoWork handler--that's independent of any and all other BackgroundWorker's. Within the DoWork handler it should only be checking one CancellationPending, the sender's (once cast to BackgroundWorker, in your case worker).
But, otherwise, calling CancelAsync from the UI is the correct way to cancel a particular BackgroundWorker.
Background workers are not "thread"s. You''re not cancelling a thread, you're cancelling the worker--which allows the DoWork handler a chance to exit before it is done it's work.
Related
I am showing a modal dialog with my background worker, but it's becoming unresponsive when some long task is done on completed event of worker thread. Can someone tell me why it is happening and how I can fix this?
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
var back = new BackgroundWorker();
back.DoWork += delegate
{
int i = 0;
while (i < 100)
{
Thread.Sleep(100);
i++;
}
};
back.RunWorkerCompleted += delegate
{
//running along task on UI therad
int i = 0;
while (i < 10000)
{
int j = 0;
while (j<10000)
{
label.Content = i.ToString();
j++;
}
i++;
}
msgbox.Close();
};
back.RunWorkerAsync();
msgbox.Title = "loading";
msgbox.Owner = this;
msgbox.ShowDialog();
}
You can't run any long-running method on the UI thread without blocking it. A single thread cannot both execute your while loop(s) and respond to user input simultaneously. This is impossible.
That's why you should execute any long-running method on a background, i.e. in the DoWork event handler in this case.
The RunWorkerCompleted event handler should only perform some quick UI related tasks, like for example updating a label or similar. Don't do anything heavy in there because then you will block the UI thread and your application will become unresponsive.
This part is executed in the UI thread:
back.RunWorkerCompleted += delegate
{
//running UI therad
int i = 0;
while (i < 100)
{
Thread.Sleep(100);
label.Content = i.ToString();
i++;
}
msgbox.Close();
};
When you call Thread.Sleep(100); you put the whole UI thread to sleep. Meaning, that your UI will sleep for 10 seconds.
I'm using A background worker for BLE RSSI level test.
my problem is that RunWorkerCompleted event is fired immediately, way before DoWork done it's operation.
most of the DoWork event operation is to create an advertisement watcher and wait for Signal from A Bluetooth low energy device.
the signal level will be updated fromthe main thread and handling of the result will be on the background worker.
here is when I call the Background worker:
...
worker = new BackgroundWorker();
worker.DoWork += callTestBLE;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.RunWorkerAsync(RSSI_Label);
}
The event handlers:
private async void callTestBLE(object sender, DoWorkEventArgs e)
{
BluetoothLEAdvertisementWatcher watcher1 ;
BluetoothLEAdvertisementFilter advertisementFilter1;
int rssiRetries1 = RSSIRETRIES;
RssiValue = "";
advertisementFilter1 = new BluetoothLEAdvertisementFilter();
try
{
advertisementFilter1.Advertisement.LocalName = myUswm.getAdvetrismentName();
checkRSSI = true;
}
catch (Exception) { checkRSSI = false; return; }
watcher1 = new BluetoothLEAdvertisementWatcher(advertisementFilter);
watcher1.ScanningMode = BluetoothLEScanningMode.Active;
watcher1.Received += OnAdvertisementReceived;
// Wait 5 seconds to make sure the device is really out of range
watcher1.SignalStrengthFilter.OutOfRangeTimeout = TimeSpan.FromMilliseconds(5000);
watcher1.SignalStrengthFilter.SamplingInterval = TimeSpan.FromMilliseconds(2000);
try
{
watcher1.Start();
await testBLEAsync();
if (myUswm.getConnectionStatus() == DISCONNECTED)
{
checkNextUUTClick(new object(), new RoutedEventArgs()); return;
}
for (int i = 0; i < 5; i++)
{
// if (RssiSamplesNum <= 0 || --rssiRetries < 0)
if (RssiSamplesNum <= 0 || --rssiRetries1 < 0)
{
//serviceList.Clear();
watcher1.Stop();
rssiRetries1 = RSSIRETRIES;
RssiSamplesNum1 = numOfAdvertismentSamples;
break;
}
else
{
((Label)e.Argument).Content = RssiValue;
/*RSSI_Label.Dispatcher.Invoke(new Action(() =>
{ RSSI_Label.Content = RssiValue; }));*/
}
Thread.Sleep(2000);
}
}
catch (Exception err) { }
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
finalizeBleTest();
}
Thanks for any help!
I agree with the other answer that BackgroundWorker is not compatible with async/await. However, I disagree that the simplest solution is to remove async in favor of BackgroundWorker. IMO, the superior solution (also resulting in simpler code) is to remove BackgroundWorker in favor of async; specifically, to replace the outdated BackgroundWorker with the superior Task.Run:
// `worker` is now `Task`.
await Task.Run(() => callTestBLE());
finalizeBleTest();
where the signature of callTestBLE is async Task, not async void.
The problem here with the async and await. BackgroundWorker is a bit outdated and do not support asynchronous code. So when you await for testBLEAsync call, callTestBLE method finishes and at that moment you have your RunWorkerCompleted event called, while actual code continue to work in the background.
So simplest solution is to completely remove async/await from your code and everything should work as expected, or, alternatively, you can rewrite your code using tasks and task continuations.
I have a timer tick event that it's interval set to 10000
private void timer1_Tick(object sender, EventArgs e)
{
Update();
}
In Update i have:
public int Update()
{
counter += 1;
int position = (int)Math.Round((counter / updateTime) * 100);
xpProgressBar1.Text = counter.ToString() + " %";
xpProgressBar1.Position = counter;
if (counter == 10)
{
DownloadingHtml();
ScrollNews();
counter = 0;
}
return position;
}
Then in the backgroundworker do work:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
int position = NewsUpdate();
object param = "report";
backgroundWorker1.ReportProgress(position, param);
}
And the backgroundworker progress event:
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
xpProgressBar1.Text = e.ProgressPercentage.ToString() + " %";
xpProgressBar1.Position = e.ProgressPercentage;
if (counter == 10)
{
DownloadingHtml();
ScrollNews();
counter = 0;
}
}
What i want to do in the first step is that the Update method will be called each 10 seconds but through the backgroundworker.
In the second step i want to add to the backgroundworker another method:
public void ScrollNews()
{
label3.Text = SaveOldHtml.HtmlLoadedFileNumber.ToString();
richTextBox1.Clear();
combindedString = string.Join(Environment.NewLine, ListsExtractions.myList);
richTextBox1.SelectAll();
richTextBox1.SelectionAlignment = HorizontalAlignment.Right;
richTextBox1.Text = combindedString;
scrollerText = string.Join(Environment.NewLine, ListsExtractions.myListWithoutLinks);
scroller1.TextToScroll = scrollerText;
if (NewsLevels.newsLevel && NewsLevels.shouldStart)
{
scroller1.Start();
NewsLevels.shouldStart = false;
}
if (NewsLevels.newsLevel == false && NewsLevels.shouldStart)
{
scroller1.Start();
NewsLevels.shouldStart = false;
}
string[] rlines = richTextBox1.Lines;
richTextBox1.SelectionStart = 0;
richTextBox1.SelectionLength = rlines[0].Length;
richTextBox1.SelectionColor = Color.Red;
richTextBox1.Select(rlines[0].Length, rlines[1].Length + 1);
richTextBox1.SelectionColor = Color.Green;
}
The ScrollNews method is being called from the Update method and it's updating richTextBox1 and Scroller1 with text.
And in the end i want to add the last method in Update:
private void DownloadingHtml()
{
using (var webClient = new WebClient())
{
webClient.Encoding = System.Text.Encoding.GetEncoding(1255);
page = webClient.DownloadString("http://rotter.net/scoopscache.html");
}
StreamWriter w = new StreamWriter(#"d:\rotterhtml\rotterscoops.html");
w.Write(page);
w.Close();
page = #"d:\rotterhtml\rotterscoops.html";
listsext.Ext(page);
count++;
}
All this methods i want to be working from the backgroundworker.
In the form1 constructor i did that first it will call the DownloadingHtml method once then call the ScrollNews method once then activate the backgroundworker and then start the timer1.
Seems like you are misusing BackgroundWorker class. It is usually used to perform a single time-consuming action that should not block th UI. All time consuming operations should take place in OnDoWork event that is executed on a separate thread. Report progress is executed on UI thread and is used to update progress bar and other UI elements that show progress.
timer1_Tick is executed on the UI thread and blocks your UI while executing. It's not a good idea to perform any downloading or processing there if you don't want your UI to hang.
You could start TPL Task, Thread or just start BackgroundWorker anew in every timer1_Tick execution. This Task or Thread can then report progress and update current UI state, calling form's thread-safe methods. BackgroundWorker can use it's own ReportProgress mechanism for this purpose.
In case of using separate Task or Thread, each method called from a separate thread should check Form's InvokeRequired and call BeginInvoke to perform thread-safe UI update. This is described well here: beginInvoke, GUI and thread and in many other similar questions.
I have a problem with background worker.
I don't know how exactly to describe it.
Actually its a game and with the background worker ever x milisecs i update the progress bar and check if anyone has lost/won or the time is up.
If someome has win the game ends.
If both players have lost/time is up the game goes to the next round.
The ploblem occurs when both players have lost. The method NextRound in the SetTime method,
runs twice.
Here is the code:
void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.SetTime(e.ProgressPercentage);
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
Thread.Sleep(3000);
BackgroundWorker worker = sender as BackgroundWorker;
int tick = ProgLib.maxTime * 10;
for (int i = 1; i <= 100; i++)
{
if ((worker.CancellationPending == true))
{
e.Cancel = true;
break;
}
else
{
// Perform a time consuming operation and report progress.
Thread.Sleep(tick);
worker.ReportProgress(i);
}
}
}
private void SetTime(double k)
{
this.time.Bar1.Value = k;
this.time.Bar2.Value = k;
if (k >= 100 || (Gallery1.hasLost() && Gallery2.hasLost()) || ((Gallery1.isWinner() || Gallery2.isWinner())))
{
if (bw == null)
return;
bw.CancelAsync();
bw.Dispose();
bw = null;
saveData();
ProgLib.isAnyoneWinner(Gallery1.isWinner(), Gallery2.isWinner());
if (ProgLib.gameHasended())
{
gameHasEnded();
}
else
{
next_round();
}
}
}
private void next_round()
{
Thread nextRoundThread = new Thread((Object Send) =>
{
MainThread.Send((Object send) =>
{
Gallery1.hidePanel.Visibility = Visibility.Visible;
Gallery2.hidePanel.Visibility = Visibility.Visible;
ProgLib.nextLetter();//goes to next letter
LetterToPlay1.setLetter(ProgLib.getArrabicLetter(ProgLib.getCurentLetter()));//sets the next letter
LetterToPlay2.setLetter(ProgLib.getArrabicLetter(ProgLib.getCurentLetter()));
}, null);
Thread SoundThread = new Thread((Object send) =>
{
//Here Must Delay enought so the animation stops the hear the bell and the the letter, and then the game starts
Thread.Sleep(1800);
ProgLib.playOtherSound(ProgLib.Sounds.Chimes);//Bell Sound
Thread.Sleep(100);
//ProgLib.PlayLetterSound(ProgLib.getCurentLetter());//Letter Sound
ProgLib.playOtherSound(ProgLib.Sounds.Cat_Yawn);//TestOnly
});
SoundThread.IsBackground = true;
SoundThread.Start();
Thread.Sleep(3000);
MainThread.Send((Object send) =>
{
Gallery1.refresh();//galleries refresh so that the magician hides.
Gallery2.refresh();//
Gallery1.hidePanel.Visibility = Visibility.Hidden;//hide the Big Magician of mistakes
Gallery2.hidePanel.Visibility = Visibility.Hidden;
}, null);
});
nextRoundThread.IsBackground = true;
nextRoundThread.Start();
bw = new BackgroundWorker();
bw.WorkerSupportsCancellation = true;
bw.WorkerReportsProgress = true;
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
bw.RunWorkerAsync();
}
There's a threading race in your code. Your worker will call ReportProgress() and immediately iterate the loop. Racing past the CancellationPending property check and falling asleep again.
Your SetTime() method runs later. And calls CancelAsync() but that doesn't have any effect at all since the worker is sleeping. Not until it wakes up again, calls ReportProgress() again, iterates the loop and then sees CancellationPending set to true.
Your SetTime() method will be called again, even though you've already ended the game.
Threading is rife with problems like this. A band-aid is to check for CancellationPending after the Sleep() call. Which works 99.999% of the time. Getting to 100% requires a pretty drastic rewrite that uses proper locking.
In a win form application, I have an array of threads which are started like this:
bool stop = false;
Thread[] threads = new Thread[10];
for (int i = 0; i < threads.Length; i++)
threads[i] = new Thread(new ThreadStart(Job));
// How to make sure all threads have exited, when the boolean = false
void Job()
{
while (!stop)
// Do something
}
Now if user press STOP, the boolean value for stop will set to true, so threads exit the Job method one after another. How can I make sure all threads are exited?
NOTE: I need traditional threading for my case and TaskLibrary doesn't fit my scenario.
Use the Join method to check if all threads have stopped.
foreach (var t in threads)
{
t.Join();
}
Have you thought about using BackgroundWorkers instead? You said "traditional threads"..I'm not exactly sure what you mean so I don't know if this is a valid proposal or not, but here it is anyways in case Join() doesn't solve your problem
BackgroundWorker[] workers = new BackgroundWorker[10];
bool allThreadsDone = false;
// initialize BackgroundWorkers
for (int i = 0; i < 10; i++)
{
workers[i] = new BackgroundWorker();
workers[i].WorkerSupportsCancellation = true;
workers[i].RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
workers[i].DoWork += new DoWorkEventHandler(AlgorithmsUI_DoWork);
workers[i].RunWorkerAsync();
}
// thread entry point..DoWork is fired when RunWorkerAsync is called
void AlgorithmsUI_DoWork(object sender, DoWorkEventArgs e)
{
while (!stop)
// do something
}
// this event is fired when the BGW finishes execution
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
bool threadsStillRunning = false;
foreach (BackgroundWorker worker in workers)
{
if (worker.IsBusy)
{
threadsStillRunning = true;
break;
}
}
if (!threadsStillRunning)
allThreadsDone = true;
}
protected override OnFormClosing(FormClosingEventArgs e)
{
if (!allThreadsDone)
{
e.Cancel = true;
MessageaBox.Show("Threads still running!");
}
}
This should prevent your form from closing if any threads are still running.
I'm not sure if this is what you're looking for, but here's a simple solution I used back in .NET 3.0 to make sure a large but deterministic number of threads had completed before continuing:
Global:
AutoResetEvent threadPoolComplete = new AutoResetEvent(false);
static int numThreadsToRun;
As you activate the threads:
numThreadsToRun = [number of threads];
[start your threads];
threadPoolComplete.WaitOne();
At the end of each thread's code:
if (Interlocked.Decrement(ref numThreadsToRun) == 0)
{
threadPoolComplete.Set();
}