I am studying parallelism and would like to know which way do you recommend for me to access other thead elements, for example, imagima I'll fill a combobox with some names, query the database I would do in parallel but I could not do a combobox.add (result) from within the task, which way do you recommend me?
a simple example to understand my question:
private void button1_Click (object sender, EventArgs e)
{
Task task = new Task (new Action (Count));
task.Start ();
}
void Count ()
{
for (int i = 0; i <99; i + +)
{
Thread.Sleep (1);
progressBar1.Value = i;
}
}
time to pass the value for the progressbar result in error
If you want to schedule a task that access UI controls, you need to pass the current synchronization context to the scheduler. If you do that the scheduler will make sure your task is executed on the correct thread. E.g.
var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(() => {
// code that access UI controls
}, uiScheduler);
For more info see http://msdn.microsoft.com/en-us/library/dd997402.aspx
You cannot access controls on another thread directly. You must invoke them first. Read this article: http://msdn.microsoft.com/en-us/library/ms171728.aspx
This is about what is would look like if you took the article and translated it for your own use: (NOT TESTED)
delegate void SetProgressBarCallback();
private void SetProgressBar()
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.progressBar1.InvokeRequired)
{
SetProgressBarCallback d = new SettProgressBarCallback(SetProgressBar);
this.Invoke(d);
}
else
{
for(int i=0; i<99; i++)
{
Thread.Sleep(1);
progressBar1.Value = i;
}
}
}
Just a quick note... the UI in WinForms can only be updated from the UI thread. Perhaps you should consider using Control.Invoke to update your progressBar1.
Ryan's answer was correct but he put the sleep inside the invoke, that caused the program to hang. Here is a example that uses the same thing he did but it does not put the sleep in the invoke.
private void button1_Click (object sender, EventArgs e)
{
Task task = new Task (new Action (Count));
task.Start ();
}
void Count ()
{
for (int i = 0; i <99; i + +)
{
Thread.Sleep (1);
if(progressBar1.InvokeRequired)
{
int j = i; //This is required to capture the variable, if you do not do this
// the delegate may not have the correct value when you run it;
progressBar1.Invoke(new Action(() => progressBar1.Value = j));
}
else
{
progressBar1.Value = i;
}
}
}
You must do the int j = i to do variable capture, otherwise it could bring up the wrong value for i inside the loop.
Related
I have been using system.threading for a while now and I trying to wrap my head around tasks. How do you make thread safe calls to a UI control (for example a text box) from another thread using the TPL?
Here is a simple example where I want to update a text box everyone 1 second with the count of my secondary thread.
I have tried a few different methods but I can't seem to get it to work.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private async void button1_Click(object sender, EventArgs e)
{
await taskAsync();
}
private Task taskAsync()
{
return Task.Factory.StartNew(() => counter());
}
private void counter()
{
for (int i = 0; i < 10000; i++)
{
Task.Delay(1000).Wait();
textBox1.Text = i.ToString();
}
}
}
Is this even possible?
Thank you
Well in your current scenario I Think that a Progress would be most suitable.
I've made some alterations to your code below:
public partial class Form1 : Form
{
Progress<int> counterProgress;
public Form1()
{
InitializeComponent();
counterProgress = new Progress<int>();
counterProgress.ProgressChanged += CounterProgressUpdated;
}
private void CounterProgressUpdated(object sender, int e)
{
textBox1.Text = e.ToString();
}
private async void button1_Click(object sender, EventArgs e)
{
await taskAsync(counterProgress);
}
private Task taskAsync(IProgress<int> progress)
{
return Task.Factory.StartNew(() => counter(progress));
}
private async Task counter(IProgress<int> progress)
{
for (int i = 0; i < 10000; i++)
{
await Task.Delay(1000);
progress.Report(i);
}
}
}
Since the progress captures the current synchronization context on construction then you should be good to go as long as you create it on the UI thread.
Any handler provided to the constructor or event handlers registered with the ProgressChanged event are invoked through a SynchronizationContext instance captured when the instance is constructed. If there is no current SynchronizationContext at the time of construction, the callbacks will be invoked on the ThreadPool.
What about something like this?
private void counter() {
for (int i = 0; i < 10000; i++) {
Thread.Sleep(1000);
// “There's never an advantage in replacing Thread.Sleep(1000); in Task.Delay(1000).Wait();”
// http://stackoverflow.com/a/29357131/4267982
Dispatcher.Invoke(() => {
textBox1.Text = i.ToString();
});
}
}
Or, as an option, another way without separate thread at all (so there's no need in synchronization):
private async Task taskAsync() {
for (int i = 0; i < 10000; i++) {
await Task.Delay(1000);
textBox1.Text = i.ToString();
}
}
How do you make thread safe calls to a UI control (for example a text box) from
another thread using the TPL?
You generall do NOT.
If you need to update the UI, then you do that using Invoke. But from TPL directly - you do not want to update the UI too often because this always is a heavy redraw and unless you make a first person shooter frame rate does not matter THAT Much. 10 updates per second are PLENTY.
In this case you may want the tasks to update a central counter (using Interlocked classes) and once that goes above a certain threshhold in changes (or using a timer running in parallel) push that into the UI.
I wanted to try out Threading.Task (C#) to run some work in parallel. In this simple example I have a form with progress bar and button. On click the RunParallel function is called. Without Task.WaitAll() it seems to run through fine. However, with the WaitAll statement the form shows and nothing happens. I dont understand what I am doing wrong in the setup below.
Thanks in advance.
public partial class MainWindow : Form
{
public delegate void BarDelegate();
public MainWindow()
{
InitializeComponent();
}
private void button_Click(object sender, EventArgs e)
{
RunParallel();
}
private void RunParallel() {
int numOfTasks = 8;
progressBar1.Maximum = numOfTasks;
progressBar1.Minimum = 0;
try
{
List<Task> allTasks = new List<Task>();
for (int i = 0; i < numOfTasks; i++)
{
allTasks.Add(Task.Factory.StartNew(() => { doWork(i); }));
}
Task.WaitAll(allTasks.ToArray());
}
catch { }
}
private void doWork(object o1)
{
// do work...
// then
this.Invoke(new BarDelegate( UpdateBar ));
}
private void UpdateBar()
{
if (progressBar1.Value < progressBar1.Maximum) progressBar1.Value++;
}
}
You are waiting on the UI thread. This freezes the UI. Don't do that.
In addition, you are deadlocking because Invoke waits for the UI thread to unblock.
My advice: use async/await if at all possible.
And please do not swallow exceptions. You're creating future work for yourself that way.
That's what WaitAll does, it blocks until all tasks have finished. The tasks can't finish because Invoke will run its action on the UI thread, which is already blocked by WaitAll
To make your code really run asynchronously, try something like this:
private void RunParallel() {
int numOfTasks = 8;
progressBar1.Maximum = numOfTasks;
progressBar1.Minimum = 0;
try
{
var context=TaskScheduler.FromCurrentSynchronizationContext()
for (int i = 0; i < numOfTasks; i++)
{
Task.Factory.StartNew(()=>DoWork(i))
.ContinueWith(()=>UpdateBar(),context);
}
}
catch (Exception exc)
{
MessageBox.Show(exc.ToString(),"AAAAAARGH");
}
}
private void DoWork(object o1)
{
// do work...
}
private void UpdateBar()
{
if (progressBar1.Value < progressBar1.Maximum) progressBar1.Value++;
}
In this case, UpdateBar is called on the UI context each time a task finishes without causing any blocking.
Note, this is not production code, just a way to show how you can run a method asynchronously and update the UI without blocking. You do need to read about Tasks to understand what they do and how they work.
Using async/await in .NET 4.5+ you can write this in a much simpler way. The following will execute DoWork in the background without blocking, but still update the UI each time a Task finishes.
private async void button1_Click(object sender, EventArgs e)
{
int numOfTasks = 8;
progressBar1.Maximum = numOfTasks;
progressBar1.Minimum = 0;
try
{
for (int i = 0; i < numOfTasks; i++)
{
await Task.Run(() => DoWork(i));
UpdateBar();
}
}
catch (Exception exc)
{
MessageBox.Show(exc.ToString(), "AAAAAARGH");
}
}
await tells the compiler to generate code to execute anything below it ont the original (UI) threadwhen the task to its right finishes:
In doWork you call this.Invoke(...) which waits for UI thread to process messages. Unfortunatelly you UI thread is not processing messages because it is waiting for all doWork(...) to finish.
Easiest fix is to change this.Invoke to this.BeginInvoke (it will send messages but no wait for them to be processed) in doWork.
Although, I have to admin it is still not by-the-book as UI should not wait for anything.
Simple pattern (pre async/await era):
Task.Factory.StartNew(() => {
... work ...
})
.ContinueWith((t) => {
... updating UI (if needed) ...
}, TaskScheduler.FromCurrentSynchronizationContext());
RunParallel blocks until all the tasks are completed. Use a different mechanism to notify the UI.
The code below is a simplified example of a problem I am having. What happens upon the form loading - the For Loop will create a new task per iteration, then go as far as entering the 'if (pic.InvokeRequired)' section, but will return back to the For Loop and continue to iterate BEFORE any of the Tasks go through their respective invocations of method() after pic.BeginInvoke() is called.
What I am trying to achieve is for the invoking to complete it's second pass through method() and eventually changing the pic.BackColor to Color.Blue. I imagine this is possible, no? I've spent a couple hours searching around and could not find a satisfactory answer to this problem..
To run this code yourself, make a new WinForms Application Project (I'm using Visual Studio 2012) and add a PictureBox called 'pic'. Insert the code below.
Thank you for any and all help!
private void Form1_Load(object sender, EventArgs e)
{
for (int i = 0; i < 5; i++)
{
Task task = Task.Factory.StartNew(() => method());
task.Wait(); //Waits for task to complete before proceeding
}
}
public delegate void delegate_method();
private void method()
{
if (pic.InvokeRequired)
{
delegate_method dm = new delegate_method(() => method());
pic.BeginInvoke(dm); //If ran once (without the loop in Form1_Load) it would call 'method()' immediately from here.
}
else
{
pic.BackColor = Color.Blue;
}
}
I can appreciate the question because in some situations blocking may be preferable to full-on async (although it's more of a last resort measure).
The answer here depends on whether your async call (the actual meat of the work which happens in the background before you get to invoke an action on the UI thread - the part of the code which I'm assuming you chose to omit for the sake of simplicity) does any UI-bound work. If it does, you're out of luck and using Application.DoEvents() is your best bet.
If, however, it does not, and you have enough control over the async code, what you can do is instead of trying to invoke the UI from within your task, pass the Action describing the work back to your UI thread (as your Task's Result) and then handle its invocation there.
Note that I've simplified the implementation of Method() as it no longer gets called from non-UI threads.
WARNING: SIMPLIFIED CODE, NOT SUITABLE FOR PRODUCTION.
using System;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace PicInvoke
{
public partial class Form1 : Form
{
public Form1()
{
this.InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Stopwatch sw;
// Sequential processing.
sw = Stopwatch.StartNew();
this.DoWorkAndBlockSequential();
sw.Stop();
MessageBox.Show(string.Format("Sequential work complete. Time taken: {0:0.000}s.", (double)sw.ElapsedMilliseconds / 1000.0));
// Parallel processing.
sw = Stopwatch.StartNew();
this.DoWorkAndBlockParallel();
sw.Stop();
MessageBox.Show(string.Format("Parallel work complete. Time taken: {0:0.000}s.", (double)sw.ElapsedMilliseconds / 1000.0));
}
private void DoWorkAndBlockSequential()
{
for (int i = 0; i < 5; i++)
{
var task = this.DoWorkAsync();
// Block the UI thread until the task has completed.
var action = task.Result;
// Invoke the delegate.
action();
}
}
private void DoWorkAndBlockParallel()
{
var tasks = Enumerable
.Range(0, 5)
.Select(_ => this.DoWorkAsync())
.ToArray();
// Block UI thread until all tasks complete.
Task.WaitAll(tasks);
foreach (var task in tasks)
{
var action = task.Result;
// Invoke the delegate.
action();
}
}
private Task<Action> DoWorkAsync()
{
// Note: this CANNOT synchronously post messages
// to the UI thread as that will cause a deadlock.
return Task
// Simulate async work.
.Delay(TimeSpan.FromSeconds(1))
// Tell the UI thread what needs to be done via Task.Result.
// We are not performing the work here - merely telling the
// caller what needs to be done.
.ContinueWith(
_ => new Action(this.Method),
TaskContinuationOptions.ExecuteSynchronously);
}
private void Method()
{
pic.BackColor = Color.Blue;
}
}
}
I'm trying to figure out how to work with the Task class. In the past I have always used the regular Thread class, but I'm trying to grasp all of the asynchronous programming...
As an example, I created a main Winforms application that has all the code.
The relevant code for my problem is:
//Relevant delegates
public delegate void MethodAction(int num);
public delegate void MethodConversion();
public delegate void OnCompletionAction(string completiontext);
//Button user presses
private void button4_Click(object sender, EventArgs e)
{
richTextBox1.Clear();
sw.Reset();
sw.Start();
Sync.RunAsync3(calcSim);
}
//The method that simulates a calculation by adding a sleep
//the input param threadlength is just to allow threads to take longer than others
//since I'm multithreading, I have to invoke the writing code on the windows RichTextbox control
private void calcSim(int threadlength)
{
string threadname = Thread.CurrentThread.Name;
for (int i = 0; i < 10; i++) //Thread calc should take 3s
{
Thread.Sleep(300 + threadlength);
richTextBox1.Invoke((MethodConversion)(() =>
{
richTextBox1.AppendText(string.Format("Thread: {0}\tVersion: {1}\n", threadname, (i + 1).ToString()));
}));
}
}
//Class that contains the different processing methods
public static class Sync
{
public static event OnCompletionAction OnProcCompletion;
public static void RunAsync3(MethodAction doM)
{
Task[] t = new Task[4];
for(int i = 0; i < 4; i++)
{
t[i] = Task.Factory.StartNew((Action)(() => { doM(50 * i); }));
}
Task.WaitAll(t);
if (OnProcCompletion != null) OnProcCompletion("RunSync method finished");
}
}
The problem lies within Task.WaitAll(t)... For some reason, which I can't figure out, it completely blocks on that line and doesn't respond anymore. If I omit that line, the form gets updated in realtime and the execution take about 3 seconds.
My question is: why isn't Task.WaitAll() blocking the UI thread for 3 seconds before releasing it and allowing the rest of the code to execute?
I know it should be blocking the UI for some time (until all threads are calculated), but it blocks the complete app endlessly. It seems to be waiting forever?
EDIT
I've been suggested to use WhenAll instead of WaitAll. I have rewritten RunAsync3 as follows:
public static void RunAsync3(MethodAction doM)
{
Task[] t = new Task[4];
for(int i = 0; i < 4; i++)
{
t[i] = Task.Factory.StartNew((Action)(() => { doM(50 * i); }));
}
//Task.WaitAll(t); -> deadlock
Task.WaitAll(new Task [] { Task.WhenAll(t) });
if (OnProcCompletion != null) OnProcCompletion("RunSync method finished");
}
But this is still getting deadlocked...? I might be using the WhenAll incorrectly?
EDIT 2
Because everybody claiming that I was blocking the UI thread were right, I decided to try this another way: by running a new thread as my calling thread inside the UI thread (so that blocking now would occur on my thread instead of UI thread). This works, but is obviously not the best way to do this!
private void button4_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ThreadStart(() =>
{
richTextBox1.Invoke((MethodConversion)(() => richTextBox1.Clear()));
sw.Reset();
sw.Start();
Sync.RunAsync3(calcSim);
}));
t.Start();
}
public static void RunAsync3(MethodAction doM)
{
Task[] t = new Task[4];
for(int i = 0; i < 4; i++)
{
t[i] = Task.Factory.StartNew((Action)(() => { doM(50 * i); }));
}
Task.WaitAll(t);
//Task.WaitAll(new Task [] { Task.WhenAll(t) });
if (OnProcCompletion != null) OnProcCompletion("RunSync method finished");
}
You're causing a deadlock.
The UI thread is waiting for 4 tasks to be completed.
On the other hand, those 4 tasks, running calcSim are trying to invoke code on the UI thread -> Deadlock.
You should be using Task.WhenAll() instead. That method will return a new task that will be marked as completed when all your for tasks have completed. If you await that task, your UI thread will be freed, and so calcSim will be able to invoke code on the UI thread, avoiding a deadlock.
Update
You're using it wrong. You're still using WaitAll, which is a blocking call. You should replace it with WhenAll.
await Task.WhenAll(t);
From the documentation:
Creates a task that will complete when all of the supplied tasks have
completed.
By calling await on the result, your UI thread will be free - until all 4 tasks complete. When that happens, your RunAsync3 method will resume.
Task.WaitAll blocks and waits for all task to complete and you are calling it on the UI thread.
All your task are trying to call richTextBox1.Invoke (in the UI thread) but your UI thread is blocked in Task.WaitAll. Deadlock.
Because it waits as your threads finish. They run exactly 3 seconds 300X10
I'm running the following code to start my threads, but they don't start as intended. For some reason, some of the threads start with the same objects (and some don't even start). If I try to debug, they start just fine (extra delay added by me clicking F10 to step through the code).
These are the functions in my forms app:
private void startWorkerThreads()
{
int numThreads = config.getAllItems().Count;
int i = 0;
foreach (ConfigurationItem tmpItem in config.getAllItems())
{
i++;
var t = new Thread(() => WorkerThread(tmpItem, i));
t.Start();
//return t;
}
}
private void WorkerThread(ConfigurationItem cfgItem, int mul)
{
for (int i = 0; i < 100; i++)
{
Thread.Sleep(10*mul);
}
this.Invoke((ThreadStart)delegate()
{
this.textBox1.Text += "Thread " + cfgItem.name + " Complete!\r\n";
this.textBox1.SelectionStart = textBox1.Text.Length;
this.textBox1.ScrollToCaret();
});
}
Anyone able to help me out?
Starting a thread doesn't really start the thread. Instead it schedules it for execution. I.e. at some point it will get to run when it is scheduled. Scheduling threads is a complex topic and an implementation detail of the OS, so your code should not expect a certain scheduling.
You're also capturing variables in your lambda. Please see this post (there is a section on Captured Variables) for the problems associated with doing that.
You just run into the (be me called) lambda error.
You provide the ConfigurationItem from the foreach loop directly. This leads to the fact, that all your threads get the same item (the last one).
To get this to work you have to create a reference for each item and apply this to each thread:
foreach (ConfigurationItem tmpItem in config.getAllItems())
{
i++;
var currentI = i;
var currentItem = tmpItem;
var t = new Thread(() => WorkerThread(currentItem, currentI));
t.Start();
//return t;
}
And you should also consider using a ThreadPool.
MSDN Description about how to use the ThreadPool
Short summary of differences here on SO
The problem seems to be there : () => WorkerThread(tmpItem, i)
I'm not used to Func<> but it seems to work like anonymous delegates in .NET 2.0. Thus, you may have a reference to the arguments of the WorkerThread() method. Hence, their values are retrieved later (when the thread actually runs).
In this case, you may already be at the next iteration of your main thread...
Try this instead :
var t = new Thread(new ParametrizedThreadStart(WorkerThread));
t.Start(new { ConfigurationItem = tmpItem, Index = i } );
[EDIT] Other implementation. More flexible if you need to pass new parameters to the thread in the future.
private void startWorkerThreads()
{
int numThreads = config.getAllItems().Count;
int i = 0;
foreach (ConfigurationItem tmpItem in config.getAllItems())
{
i++;
var wt = new WorkerThread(tmpItem, i);
wt.Start();
//return t;
}
}
private class WorkerThread
{
private ConfigurationItem _cfgItem;
private int _mul;
private Thread _thread;
public WorkerThread(ConfigurationItem cfgItem, int mul) {
_cfgItem = cfgItem;
_mul = mul;
}
public void Start()
{
_thread = new Thread(Run);
_thread.Start();
}
private void Run()
{
for (int i = 0; i < 100; i++)
{
Thread.Sleep(10 * _mul);
}
this.Invoke((ThreadStart)delegate()
{
this.textBox1.Text += "Thread " + _cfgItem.name + " Complete!\r\n";
this.textBox1.SelectionStart = textBox1.Text.Length;
this.textBox1.ScrollToCaret();
});
}
}
Do you really need to spawn threads manually (which is a rather expensive task) ? You could try to switch to the ThreadPool instead.
You can't assume that the threads will run in the same order they were called, unless you force it, and cause a dependency between them.
So the real question is - what is your goal ?
I think that the error is somewhere else. Here are some hints to help you debug :
Give a name containing to each thread, and display the thread name instead of the config item name :
this.textBox1.Text += "Thread " + Thread.Current.Name + " Complete!\r\n";
Display the content of config.getAllItems(), may be that some items has the same name (duplicated)
===========
Here are some additional information about multi threading with winforms:
dont create new Thread directly, use the ThreadPool instead :
ThreadPool.QueueUserWorkItem(state => { WorkerThread(tmpItem, i); });
If you really want to creat your threads, use this.BeginInvoke instead of this.Invoke your worker thread will finish sooner => less concurrent thread => better global performance
don't call Thread.Sleep in a loop, just do a big sleep: Thread.Sleep(10*mul*100);
I hope that this will help you.
Thanks to all of you!
I just implemented the threadpool, and that worked like a charm - with the added bonus of not spawning too many threads at once.
I'll have a look at the other solutions, too, but this time around the threadpool will save me from having to manually check for bozos with too many configs ;)