Parallel.ForEach freezing on last loop [duplicate] - c#

More newbie questions:
This code grabs a number of proxies from the list in the main window (I couldn't figure out how to make variables be available between different functions) and does a check on each one (simple httpwebrequest) and then adds them to a list called finishedProxies.
For some reason when I press the start button, the whole program hangs up. I was under the impression that Parallel creates separate threads for each action leaving the UI thread alone so that it's responsive?
private void start_Click(object sender, RoutedEventArgs e)
{
// Populate a list of proxies
List<string> proxies = new List<string>();
List<string> finishedProxies = new List<string>();
foreach (string proxy in proxiesList.Items)
{
proxies.Add(proxy);
}
Parallel.ForEach<string>(proxies, (i) =>
{
string checkResult;
checkResult = checkProxy(i);
finishedProxies.Add(checkResult);
// update ui
/*
status.Dispatcher.Invoke(
System.Windows.Threading.DispatcherPriority.Normal,
new Action(
delegate()
{
status.Content = "hello" + checkResult;
}
)); */
// update ui finished
//Console.WriteLine("[{0}] F({1}) = {2}", Thread.CurrentThread.Name, i, CalculateFibonacciNumber(i));
});
}
I've tried using the code that's commented out to make changes to the UI inside the Parallel.Foreach and it makes the program freeze after the start button is pressed. It's worked for me before but I used Thread class.
How can I update the UI from inside the Parallel.Foreach and how do I make Parallel.Foreach work so that it doesn't make the UI freeze up while it's working?
Here's the whole code.

You must not start the parallel processing in your UI thread. See the example under the "Avoid Executing Parallel Loops on the UI Thread" header in this page.
Update: Or, you can simply create a new thread manuall and start the processing inside that as I see you have done. There's nothing wrong with that too.
Also, as Jim Mischel points out, you are accessing the lists from multiple threads at the same time, so there are race conditions there. Either substitute ConcurrentBag for List, or wrap the lists inside a lock statement each time you access them.

A good way to circumvent the problems of not being able to write to the UI thread when using Parallel statements is to use the Task Factory and delegates, see the following code, I used this to iterate over a series of files in a directory, and process them in a Parallel.ForEach loop, after each file is processed the UI thread is signaled and updated:
var files = GetFiles(directoryToScan);
tokenSource = new CancellationTokenSource();
CancellationToken ct = tokenSource.Token;
Task task = Task.Factory.StartNew(delegate
{
// Were we already canceled?
ct.ThrowIfCancellationRequested();
Parallel.ForEach(files, currentFile =>
{
// Poll on this property if you have to do
// other cleanup before throwing.
if (ct.IsCancellationRequested)
{
// Clean up here, then...
ct.ThrowIfCancellationRequested();
}
ProcessFile(directoryToScan, currentFile, directoryToOutput);
// Update calling thread's UI
BeginInvoke((Action)(() =>
{
WriteProgress(currentFile);
}));
});
}, tokenSource.Token); // Pass same token to StartNew.
task.ContinueWith((t) =>
BeginInvoke((Action)(() =>
{
SignalCompletion(sw);
}))
);
And the methods that do the actual UI changes:
void WriteProgress(string fileName)
{
progressBar.Visible = true;
lblResizeProgressAmount.Visible = true;
lblResizeProgress.Visible = true;
progressBar.Value += 1;
Interlocked.Increment(ref counter);
lblResizeProgressAmount.Text = counter.ToString();
ListViewItem lvi = new ListViewItem(fileName);
listView1.Items.Add(lvi);
listView1.FullRowSelect = true;
}
private void SignalCompletion(Stopwatch sw)
{
sw.Stop();
if (tokenSource.IsCancellationRequested)
{
InitializeFields();
lblFinished.Visible = true;
lblFinished.Text = String.Format("Processing was cancelled after {0}", sw.Elapsed.ToString());
}
else
{
lblFinished.Visible = true;
if (counter > 0)
{
lblFinished.Text = String.Format("Resized {0} images in {1}", counter, sw.Elapsed.ToString());
}
else
{
lblFinished.Text = "Nothing to resize";
}
}
}
Hope this helps!

If anyone's curious, I kinda figured it out but I'm not sure if that's good programming or any way to deal with the issue.
I created a new thread like so:
Thread t = new Thread(do_checks);
t.Start();
and put away all of the parallel stuff inside of do_checks().
Seems to be doing okay.

One problem with your code is that you're calling FinishedProxies.Add from multiple threads concurrently. That's going to cause a problem because List<T> isn't thread-safe. You'll need to protect it with a lock or some other synchronization primitive, or use a concurrent collection.
Whether that causes the UI lockup, I don't know. Without more information, it's hard to say. If the proxies list is very long and checkProxy doesn't take long to execute, then your tasks will all queue up behind that Invoke call. That's going to cause a whole bunch of pending UI updates. That will lock up the UI because the UI thread is busy servicing those queued requests.

This is what I think might be happening in your code-base.
Normal Scenario: You click on button. Do not use Parallel.Foreach loop. Use Dispatcher class and push the code to run on separate thread in background. Once the background thread is done processing, it will invoke the main UI thread for updating the UI. In this scenario, the background thread(invoked via Dispatcher) knows about the main UI thread, which it needs to callback. Or simply said the main UI thread has its own identity.
Using Parallel.Foreach loop: Once you invoke Paralle.Foreach loop, the framework uses the threadpool thread. ThreadPool threads are chosen randomly and the executing code should never make any assumption on the identity of the chosen thread. In the original code its very much possible that dispatcher thread invoked via Parallel.Foreach loop is not able to figure out the thread which it is associated with. When you use explicit thread, then it works fine because the explicit thread has its own identity which can be relied upon by the executing code.
Ideally if your main concern is all about keeping UI responsive, then you should first use the Dispatcher class to push the code in background thread and then in there use what ever logic you want to speedup the overall execution.

if you want to use parallel foreach in GUI control like button click etc
then put parallel foreach in Task.Factory.StartNew
like
private void start_Click(object sender, EventArgs e)
{
await Task.Factory.StartNew(() =>
Parallel.ForEach(YourArrayList, (ArraySingleValue) =>
{
Console.WriteLine("your background process code goes here for:"+ArraySingleValue);
})
);
}//func end
it will resolve freeze/stuck or hang issue

Related

Semaphore in KeyUp event handler -- locks keyboard input

I'm trying to understand Semaphore's.
In short, I've placed a "long" running procedure (which accesses Network resources), InitializeNamesAsync("","",""), in a KeyUp event handler. I'm trying to allow the user to do continuous typing without slowdown while viewNames is being initialized by InitializeNamesAsync(). Since the user will be continuously typing, the KeyUp event handler will be called many times while the InitializeNamesAsync() method is running.
While the below code compiles fine, it locks up forever completely stopping keyboard input.
So my questions are:
is this an appropriate use of Semaphore's?
how can I make this work?
Is there a better way?
TIA
Having defined
ResourceLock = new Semaphore(0, 1);
private async void _cboLastName_KeyUpAsync(object sender, KeyEventArgs e)
{
if (viewNames == null)
{
ResourceLock.WaitOne();
await InitializeNamesAsync("", "", "");
ResourceLock.Release();
}
}
There's fundamental issue with your design, though you are using the Semaphore to allow multiple threads to enter and execute the event inside the critical region, but challenge is, which thread are you blocking?
As the event is executed on the Ui thread, which is just 1 and unique, what's happening is:
Your code enters the Event, Calls the WaitOne for the Semaphore on the Ui Thread and it's done you are blocked, it doesn't even execute the Async method as expected
Check the out the following Console code, what do you think is the result ?
Following code leads to Deadlock, since Ui or Main Console Thread is waiting upon itself
async Task Main()
{
Semaphore s = new Semaphore(0, 2);
for(int x = 0; x < 5;x++)
{
s.WaitOne();
await Test(x);
s.Release();
}
}
async Task Test(int x)
{
$"Entering : {x}".Dump();
await Task.Delay(3000);
}
In above code await Test(x); and s.Release(); are never called
What are the options, review modified design:
async Task Main()
{
for(int x = 0; x < 5;x++)
{
await Test(x);
s.WaitOne();
}
}
Semaphore s = new Semaphore(0,2);
async Task Test(int x)
{
$"Entering : {x}".Dump();
await Task.Delay(3000);
s.Release();
}
What's different here:
Async method was called before the Semaphore WaitOne is called
Semaphore Release happens post the finish of Async method, not on same thread (in this case on threadpool thread)
And you will find this code will execute successfully without any deadlock
What's the solution:
Don't call WaitOne on a unique thread like Ui thread, that's a recipe for deadlock, especially when Release is also scheduled on same thread
Call Release on a separate thread (I have used the Async method, which is using Threadpool thread in this case)
Other Details:
Ideally Semaphore is meant for the multiple threads to enter the critical region, if you are expecting only one thread, then Sempahore may not be the right choice, but it helps signaling threads unlike lock, you may also review ManualResetEvent and AutoResetEvent, which supports Signaling / EventWaitHandle use cases
The thread is blocked because you enter it twice and semaphore doesn't allow enter the same thread twice(while e.g. Monitor.Enter allows - but then it is not clear why would you need it here).
As I understand you need to launch initialization in the background.
Since it is UI thread you might not need to use synchronization primitives(in this case, at least, not in general). I think it would be enough just having two variables like
beingInitialized
and initialized with the code like
private async void EnsureInitialized()
{
if(!initialized && !beingInitialized)
{
beingInitalized = true;
await StartInitialization();
initalized = true;
beingInitialized = false;
}
}
And call it then as fire and forget
like
private async void _cboLastName_KeyUpAsync(object sender, KeyEventArgs e)
{
EnsureInitialized();
...

A thread is still trying to access a disposed form?

Basically, I have a thread that downloads and reports the download status to a progress bar and a label. It always crashes when trying to invoke a object in a disposed form (Progress bar & label) even when there's a if (!this.Disposed) is called before, and still throws the exception even with a catch (ObjectDisposedException) is called in the same try block. I'm not sure what I can do to fix this, it's probably best described as the most annoying thing I've ever encountered.
Thanks you.
Update (from a considerate SO lurker) of my source found on pastebin
Thread downloader();
public bool abortThread = false();
private void frmDownload_FormClosing(object sender, FormClosingEventArgs e) {
downloader.Abort(); // Abort the thread before closing the form...?
abortThread = true; // Set the abortThread to true
this.Dispose(); // Dispose thread
}
downloader = new Thread(() => {
string[] URLs = { "http://test1.com/", "http://test2.com/", "http://test3.com/" };
try {
using (WebClient wc = new WebClient()) {
wc.DownloadProgressChanged += (s, e) => {
if (!pbDownloadStatus.IsDisposed && !lbPercentage.IsDisposed) {
if (!abortThread) {
this.Invoke((MethodInvoker)(() => pbDownloadStatus.Value = e.ProgressPercentage)); // EXCEPTION HAPPENS HERE
this.Invoke((MethodInvoker)(() => pbDownloadStatus.Value++));
this.Invoke((MethodInvoker)(() => pbDownloadStatus.Value--));
this.Invoke((MethodInvoker)(() => lbPercentage.Text = e.ProgressPercentage.ToString() + "%"));
}
}
};
wc.DownloadFileCompleted += (s, e) => {
if (!pbDownloadStatus.IsDisposed && !lbPercentage.IsDisposed) {
lock (e.UserState) {
this.Invoke((MethodInvoker)(() => pbDownloadStatus.Value = 0));
this.Invoke((MethodInvoker)(() => lbPercentage.Text = "0%"));
Monitor.Pulse(e.UserState);
}
}
};
wc.Proxy = WebProxy.GetDefaultProxy();
wc.Headers.Add(header);
for (int i = 0; i < URLs.Length; i++) {
var sync = new Object();
lock (sync) {
wc.DownloadFileAsycn(new Uri(URLs[i]), "C:\Test\URL" + i);
Monitor.Wait(sync);
}
}
}
}
}
catch (ObjectDisposedException disEx) { // Never gets caught
downloader.Abort();
MessageBox.Show("Object was disposed");
}
});
downloader.Start();
From Msdn
Beginning with the .NET Framework 4, multithreaded programming is
greatly simplified with the System.Threading.Tasks.Parallel and
System.Threading.Tasks.Task classes, Parallel LINQ (PLINQ), new
concurrent collection classes in the System.Collections.Concurrent
namespace, and a new programming model that is based on the concept of
tasks rather than threads
The need to work with threads directly in the modern era is greatly reduced, and you should probably look at Tasks and async/await Tasks can be cancelled, are easier to manage and async returns back to the calling context.
Secondly, your code doesn't make sense, and its full of compiler errors which is not a good start for a question. Additionally, since there is so much wrong with the code i have decided to just give you lots of points to think about apposed to rewriting it all
So lets look at some of the more obvious issues this code has.
abortThread is accessed from multiple threads and is not thread safe for the most part.
You are calling var sync = new Object(); directly before lock (sync) meaning you are locking nothing
Even if that lock statement was going to work, there is no other thread using the lock, meaning its redundant.
You are calling this.Dispose() from the forms closing event. This is unusal to say the least
The two conditions when a form is not disposed on Close is when (1) it
is part of a multiple-document interface (MDI) application, and the
form is not visible; and (2) you have displayed the form using
ShowDialog. In these cases, you will need to call Dispose manually to
mark all of the form's controls for garbage collection.
Basically in a non MDI application, If you call ShowDialog then put it in a using statement.
You are trying to check IsDisposed to determine if its safe to marshal back to the UI thread.
Just because you call Dispose doesn't mean the form IS disposed, this is not how it works and will not solve your problem.
If you need to do asynchronous IO bound work, Use the aysnc,await pattern, then you wont be blocking a thread for spurious reasons waiting for a completion port. If you need to run this in parallel, then consider DataFlow with action blocks so you can take advantage of aysnc,await and parallel.
If you need to determine whether a form is alive or dead, use a thread safe variable. Use a static Lock object, and every where you update the variable use lock as well.
if you need to marshal to the UI thread. Don't do this.Invoke((MethodInvoker)(() multiple times, Do it once, and update everything at once.

Notifying about task finishing its work

I'm thinking of a simple way of reacting on task finishing its work. I came up with the following solution (paste it to WinForms application with a single button to test):
public partial class Form1 : Form
{
private Thread thread;
public void DoFinishWork() {
// [4]
// UI thread - waiting for thread to finalize its work
thread.Join();
// Checking, if it really finished its work
MessageBox.Show("Thread state: " + thread.IsAlive.ToString());
}
public void DoWork() {
// [2]
// Working hard
Thread.Sleep(1000);
}
public void FinishWork() {
// [3]
// Asynchronously notifying form in main thread, that work was done
Delegate del = new Action(DoFinishWork);
this.BeginInvoke(del);
// Finalizing work - this should be switched
// at some point to main thread
Thread.Sleep(1000);
}
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e) {
// [1]
// Schedule the task
ThreadStart start = new ThreadStart(DoWork);
// Schedule notification about finishing work
start += FinishWork;
thread = new Thread(start);
thread.Start();
}
}
This is meant to be a simple cancel scenario, so there will be only one thread, which will be running in parallel to the UI thread.
Is there a simpler (or more thread-safe) way of implementing this kind of notification for the Thread?
Please take into consideration two facts:
The only way i can terminate the thread is to Abort it (that's because I have no control over what is being done in the thread - 3rd party code)
Thus, I cannot use BackgroundWorker, because it only provides way of graceful termination.
Is there a simpler (or more thread-safe) way of implementing this kind of notification for the Thread?
Yes, use the TPL and let the framework worry about managing the thread
Task.StartNew(() => {
// do some stuff
}).ContinueWith((task) => {
// do some stuff after I have finished doing some other stuff
});
Or alternatively, since you are working with WinForms, use a BackgroundWorker and handle the RunWorkerCompleted event.
I mistook your notion of kill for cancel - there is no reliable way of actually killing a thread in .NET, even the documentation suggests that using Abort is more or less a gamble and gives absolutely no guarentees that the thread will actually be killed. Also, it will leave the thread and, as a consequence, the application in an unpredictable state so if you are willing to take that risk then that's up to you.
One alternative is to simply let the thread play out but just ignore the results, depending on the size of the task it might not be that big a deal.
Although you need Abort to kill the thread, you can still use the TPL. You could start that thread within the task, and wait for it as well as for an CancellationToken. When the task is cancelled before the thread finishes, you can call Abort on the thread.
It would look something like that:
// In your class:
ManualResetEvent threadFinished = new ManualResetEvent(false);
// In your calling function (button1_Click):
Task.Run( () => {
ThreadStart threadStart = new StreadStart(DoWork);
threadStart += () => { threadFinished.Set(); }
Thread thread = new Thread(threadStart);
threadFinished.Reset();
thread.Start();
WaitHandle waitCancel = cancellationToken.WaitHandle;
int waited = WaitHandle.WaitAny( new WaitHandle[]{ waitCancel, threadFinished } );
if (waited == 0 && cancellationToken.IsCancellationRequested)
thread.Abort();
else
thread.Join()
});

Dispatcher.Invoke from a new thread is locking my UI

i'm using wpf, there's a button on my ui.
when the user clicks it, i have a for loop that runs a new method, on a new thread using autoresetevent.
in that method on that new thread, i'm using a label, let's call it lblStatus. i want to update that label on this thread that's not on the ui. using wpf, i have to use Dispatcher.Invoke.
here's a sample of my code:
Thread thread= new Thread(StartLooking);
thread.Start();
_waitHandle.WaitOne();
private void StartLooking(object value)
{
if (lblStatus.Dispatcher.Thread == Thread.CurrentThread)
{
lblStatus.Content = "Scanning>...";
}
else
{
lblStatus.Dispatcher.Invoke(DispatcherPriority.Background, new Action(() => lblStatus.Content = "Scanning>>>>>"));
}
_waitHandle.Set();
}
the program just stops here. it doesn't change the content of the label, it returns to my ui, but blocks it.
i've tried
lblStatus.Dispatcher.Invoke(DispatcherPriority.Normal, new LblStatusThreadCheck(lblStatusThreadCheck), "Scanning...");
as well, but that isn't working also. any ideas?
The problem is that you're making it impossible for this to execute, since you're using Invoke.
Dispatcher.Invoke will not return until the UI thread processes. However, you've blocked the UI thread by calling _waitHandle.WaitOne();, and don't set the wait handle until AFTER this processes. The two effectively cause a dead lock.
If you switch this to use BeginInvoke instead, the UI will queue the element, the wait handle will set, THEN the label will update. It will work and not block, however.
Since the two previous posts already cover the problem in your code, just a suggestion: instead of
if (lblStatus.Dispatcher.Thread == Thread.CurrentThread)
try using
if (!lblStatus.CheckAccess())
It's cleaner and has the exact intent you want. Just read about it here.
You probably want to use BeginInvoke instead. Invoke will block the thread that called it until the UI thread has run the Action, and since you're setting the priority to Background, this could take some time.
Best solution I have found for .net 4.5+ is using SynchronizationContext Post
Example (Task.Run's can be as many as you want in parallel accessing UI):
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
var context = SynchronizationContext.Current;
Task.Run(() =>
{
var i = 0;
while (true)
{
context.Post((tmp) =>
{
uiText.Text = $"{i}";
}), this);
Thread.Sleep(1000);
i++;
}
});
}

c# Thread issue using Invoke from a background thread

I've got thread, which processes some analytic work.
private static void ThreadProc(object obj)
{
var grid = (DataGridView)obj;
foreach (DataGridViewRow row in grid.Rows)
{
if (Parser.GetPreparationByClientNameForSynonims(row.Cells["Prep"].Value.ToString()) != null)
UpdateGridSafe(grid,row.Index,1);
Thread.Sleep(10);
}
}
I want safely update my gridView at loop, so I use classic way:
private delegate void UpdateGridDelegate(DataGridView grid, int rowIdx, int type);
public static void UpdateGridSafe(DataGridView grid, int rowIdx, int type)
{
if (grid.InvokeRequired)
{
grid.Invoke(new UpdateGridDelegate(UpdateGridSafe), new object[] { grid, rowIdx, type });
}
else
{
if (type == 1)
grid.Rows[rowIdx].Cells["Prep"].Style.ForeColor = Color.Red;
if (type==2)
grid.Rows[rowIdx].Cells["Prep"].Style.ForeColor = Color.ForestGreen;
}
}
But when I enter UpdateGridSafe, the program hangs.
In the debugger, I see that grid.Invoke doesn't invoke UpdateGridSafe. Please help - what's wrong?
EDIT
Classic thread create code
Thread t = new Thread(new ParameterizedThreadStart(ThreadProc));
t.Start(dgvSource);
t.Join();
MessageBox.Show("Done", "Info");
You have a deadlock. Your t.Join is blocking the GUI thread until ThreadProc is done. ThreadProc is blocked waiting for t.Join to finish so it can do the Invokes.
Bad Code
Thread t = new Thread(new ParameterizedThreadStart(ThreadProc));
t.Start(dgvSource);
t.Join(); <--- DEADLOCK YOUR PROGRAM
MessageBox.Show("Done", "Info");
Good Code
backgroundWorker1.RunWorkerAsync
private void backgroundWorker1_DoWork(object sender,
DoWorkEventArgs e)
{
var grid = (DataGridView)obj;
foreach (DataGridViewRow row in grid.Rows)
{
if (Parser.GetPreparationByClientNameForSynonims(row.Cells["Prep"].Value.ToString()) != null)
UpdateGridSafe(grid,row.Index,1);
// don't need this Thread.Sleep(10);
}
}
private void backgroundWorker1_RunWorkerCompleted(
object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("Done", "Info");
}
EDIT
Also use BeginInvoke instead of Invoke. That way your worker thread doesn't have to block every time you update the GUI.
Reference
Avoid Invoke(), prefer BeginInvoke()
It's because you're joining on your worker thread. Your UI thread starts the background thread, then calls Join on it. This stops the UI thread from performing any other actions.
During this, the background thread is doing its work and calling Invoke, which waits for the UI thread to respond. Because the UI thread is waiting for a Join, it won't ever process the request to invoke. Hence, deadlock.
What you should do, is eliminate the Join and the MessageBox. Put the MessageBox into its own function.
void NotifyDone() {
if( InvokeRequired ) BeginInvoke( (MethodInvoker) NotifyDone );
else {
// Perform any post-processing work
MessageBox.Show("Done", "Info");
}
}
When the background thread is done, simply call this method (and eliminate static from ThreadProc).
private void ThreadProc(object obj)
{
var grid = (DataGridView)obj;
foreach (DataGridViewRow row in grid.Rows)
{
if (Parser.GetPreparationByClientNameForSynonims(row.Cells["Prep"].Value.ToString()) != null)
UpdateGridSafe(grid,row.Index,1);
Thread.Sleep(10);
}
NotifyDone();
}
And like everyone else has already said, the use of Sleep, especially at such a low interval is either dangerous, misleading or worthless. I'm in the count it worthless camp.
The Invoke statement will wait until the main thread's message pump isn't busy, and can handle a new message. If your main thread is busy, the Invoke will hang.
In your case, it looks like your top code is running in a tight loop, so there's never a chance for the Invoke in the bottom code to actually run. If you change the Thread.Sleep in your upper code block to something with a time in it, hopefully that will give your main thread a chance to handle the .Invoke call.
Depending on what your main application thread is doing, you may need to actually finish your first loop before any of the .Invoke calls will run - if that's the case, I can post some modified code that might work better.
Never, ever, every use Thread.Sleep(0). It doesn't do what you think it does and will cause you nothing but pain. For example, in a tight loop the OS may decide that the thread that just slept is the next one to run. As a result you won't actually yield the thread.
Try your code again using Thread.Sleep(1) every N iterations where N is about 0.25 to 1.0 seconds worth of work.
If that doesn't work let me know and we can look at how ThreadProc is created.
References
Never Sleep(0) in an Infinite Loop
EDIT
Argument for never using Thread.Sleep
Thread.Sleep is a sign of a poorly designed program.
You also could be having issues accessing the grid at the same time from different threads. DataTables are not thread safe, so I'd guess that DataGridView isn't either. Here's some sample code from this article on DataRow and Concurrency where you would use Monitor.Enter and Montori.Exit to get some concurrency in place.
public void DoWorkUpdatingRow(object state)
{
List<DataRow> rowsToWorkOn = (List<DataRow>)state;
foreach (DataRow dr in rowsToWorkOn)
{
Monitor.Enter(this);
try
{
dr["value"] = dr["id"] + " new value";
}
finally
{
Monitor.Exit(this);
}
}
}

Categories

Resources