Queue of BackgroundWorkers raise event when complete [closed] - c#

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I need to execute n BackgroundWorkers, when they're complete I want to raise an event and do something with the result of all their work. My use case it to make the queue, fill it, then run it only once. To accomplish this I made a class ParallelQueue. With my initial testing it seems to work, however I'm concerned that the condition _max == _iteration is not the best was to evaluate all work in the queue has been done. Or that my use of Queue is not thread safe, what should I use to accomplish this? (ConcurrentQueue?) If this question is too general I'll remove it, Thanks.
public class ParallelQueue
{
private Queue<BackgroundWorker> _queue;
private readonly object _key = new object();
private int _max = 0;
private int _iteration = 0;
private bool _ran = false;
public ParallelQueue()
{
_queue = new Queue<BackgroundWorker>();
}
public delegate void BackgroundQueueCompleted(object sender, RunWorkerCompletedEventArgs e);
public event BackgroundQueueCompleted QueueCompleted;
public void Add(BackgroundWorker worker)
{
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(WorkerCompleted);
_queue.Enqueue(worker);
}
public void Run()
{
lock (_key)
{
if(!_queue.Any()) throw new ArgumentOutOfRangeException("ParallelQueue cannot be empty");
if (_ran) throw new InvalidOperationException("ParallelQueue can only be run once");
_ran = true;
_max = _queue.Count();
Parallel.For(0, _queue.Count, (i, state) =>
{
BackgroundWorker worker = _queue.Dequeue();
worker.RunWorkerAsync();
});
}
}
private void WorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Interlocked.Increment(ref _iteration);
if (_max == _iteration)
{
QueueCompleted?.Invoke(this, e);
}
}
}
example using ParallelQueue
public class Program
{
static void Main(string[] args)
{
var queue = new ParallelQueue();
queue.QueueCompleted += MyQueueCompletedHandler;
for (int i = 0; i < 10; i++)
{
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler((sender, e) =>
{
Thread.Sleep(500);
});
queue.Add(bw);
}
queue.Run();
Console.ReadLine();
}
private static void MyQueueCompletedHandler(object sender, RunWorkerCompletedEventArgs e)
{
Console.WriteLine("queue is complete");
}
}

The BackgroundWorker class has become practically obsolete after the introduction of the Task Parallel Library (TPL) in 2010. If the results of the work you have to do is homogeneous, you can just use the Parallel.ForEach method, or, if you are familiar with LINQ, use PLINQ. Here is a PLINQ example:
var input = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int[] results = input
.AsParallel()
.AsOrdered() // optional
.WithDegreeOfParallelism(2) // optional
.Select(x => { Thread.Sleep(500); return x * 2; }) // simulate some work
.ToArray();
If the results are heterogeneous, you can create a Task<TResult> for each piece of work, store it in a List<Task>, wait all the tasks, and get the results through the Result property of each. Example:
var task1 = Task.Run(() => { Thread.Sleep(500); return 1; });
var task2 = Task.Run(() => { Thread.Sleep(500); return "Helen"; });
var task3 = Task.Run(() => { Thread.Sleep(500); return DateTime.Now; });
var list = new List<Task>() { task1, task2, task3 };
Task.WaitAll(list.ToArray());
int result1 = task1.Result;
string result2 = task2.Result;
DateTime result3 = task3.Result;

Related

How do i stop pause a task in c# .net

I have tried but it is not working i want to stop and pause this task:: code below
private void checkingTimer()
{
System.Windows.Threading.DispatcherTimer dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
dispatcherTimer.Tick += new EventHandler(startPollingAwaitingURLs);
dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 1000);
dispatcherTimer.Start();
}
private static object _lock_CrawlingSync = new object();
private static bool blBeingProcessed = false;
private static List<Task> lstCrawlingTasks = new List<Task>();
private static List<string> lstCurrentlyCrawlingUrls = new List<string>();
private void btnTest_Click(object sender, RoutedEventArgs e)
{
using (WebCrawlerEntities1 db = new WebCrawlerEntities1())
{
db.tblMainUrls.RemoveRange(db.tblMainUrls);
db.SaveChanges();
}
}
private void clearDBandStart(object sender, RoutedEventArgs e)
{
dtStartDate = DateTime.Now;
crawlPage(urlTextbox.Text.normalizeUrl(), 0, urlTextbox.Text.normalizeUrl(), DateTime.Now);
checkingTimer();
}
private void startPollingAwaitingURLs(object sender, EventArgs e)
{
lock (UserLogs)
{
string srPerMinCrawlingspeed = (irCrawledUrlCount.ToDouble() / (DateTime.Now - dtStartDate).TotalMinutes).ToString("N2");
string srPerMinDiscoveredLinkSpeed = (irDiscoveredUrlCount.ToDouble() / (DateTime.Now - dtStartDate).TotalMinutes).ToString("N2");
string srPassedTime = (DateTime.Now - dtStartDate).TotalMinutes.ToString("N2");
UserLogs.Insert(0, $"{DateTime.Now} polling awaiting urls \t processing: {blBeingProcessed} \t number of crawling tasks: {lstCrawlingTasks.Count}");
UserLogs.Insert(0, $"Total Time: {srPassedTime} Minutes \t Total Crawled Links Count: {irCrawledUrlCount.ToString("N0")} \t Crawling Speed Per Minute: {srPerMinCrawlingspeed} \t Total Discovered Links : {irDiscoveredUrlCount.ToString("N0")} \t Discovered Url Speed: {srPerMinDiscoveredLinkSpeed} ");
}
logMesssage($"polling awaiting urls \t processing: {blBeingProcessed} \t number of crawling tasks: {lstCrawlingTasks.Count}");
if (blBeingProcessed)
return;
lock (_lock_CrawlingSync)
{
blBeingProcessed = true;
lstCrawlingTasks = lstCrawlingTasks.Where(pr => pr.Status != TaskStatus.RanToCompletion && pr.Status != TaskStatus.Faulted).ToList();
int irTasksCountToStart = _irNumberOfTotalConcurrentCrawling - lstCrawlingTasks.Count;
if (irTasksCountToStart > 0)
using (WebCrawlerEntities1 db = new WebCrawlerEntities1())
{
var vrReturnedList = db.tblMainUrls.Where(x => x.isCrawled == false && x.CrawlTryCounter < _irMaximumTryCount)
.OrderBy(pr => pr.DiscoverDate)
.Select(x => new
{
x.Url,
x.LinkDepthLevel
}).Take(irTasksCountToStart * 2).ToList();
logMesssage(string.Join(" , ", vrReturnedList.Select(pr => pr.Url)));
foreach (var vrPerReturned in vrReturnedList)
{
var vrUrlToCrawl = vrPerReturned.Url;
int irDepth = vrPerReturned.LinkDepthLevel;
lock (lstCurrentlyCrawlingUrls)
{
if (lstCurrentlyCrawlingUrls.Contains(vrUrlToCrawl))
{
logMesssage($"bypass url since already crawling: \t {vrUrlToCrawl}");
continue;
}
lstCurrentlyCrawlingUrls.Add(vrUrlToCrawl);
}
logMesssage($"starting crawling url: \t {vrUrlToCrawl}");
lock (UserLogs)
{
UserLogs.Insert(0, $"{DateTime.Now} starting crawling url: \t {vrUrlToCrawl}");
}
var vrStartedTask = Task.Factory.StartNew(() => { crawlPage(vrUrlToCrawl, irDepth, null, DateTime.MinValue); }).ContinueWith((pr) =>
{
lock (lstCurrentlyCrawlingUrls)
{
lstCurrentlyCrawlingUrls.Remove(vrUrlToCrawl);
logMesssage($"removing url from list since task completed: \t {vrUrlToCrawl}");
}
});
lstCrawlingTasks.Add(vrStartedTask);
if (lstCrawlingTasks.Count > _irNumberOfTotalConcurrentCrawling)
break;
}
}
blBeingProcessed = false;
}
}
so is there a way to stop my task up ahead and pause should i mre.set() or .Set()
my application is a web crawler that get links from any website.
so when pressing on a button web crawling task pause or stop and restart ... any methods to do or changes
Try :
Thread.Sleep() to pause your task.
Thread.Interrupt() to stop your sleeping task.
Technically you can't stop a Task. Task isn't running anything but only waiting for a completion of something it was bound for. You can stop the code, running in the Thread. For example, with ManualResetEventSlim.
private readonly ManualResetEventSlim _mre = new ManualResetEventSlim(true); // not paused initially
public void Pause()
{
_mre.Reset();
}
public void Resume()
{
_mre.Set();
}
In the method where you want to pause the execution when requested, just add.
_mre.Wait();
Few tips
Use Task.Run instead of Task.Factory.StartNew and learn the difference.
Find something about Producer/Consumer programming pattern and related thread-safe collections.
Say hello to Asynchronous programming.

How to properly detect when multiple threads within another thread are fully complete?

I'm running several BackgroundWorkerthreads that are being used to execute queries to retrieve DataSets all within another BackgroundWorker thread. Let's call the thread that is running these multiple threads the 'Host Thread' and the others 'Query Thread'. What I am trying to do is to tell when all of the query threads are finished populating their DataSets by utilizing the host thread's RunWorkerCompleted event. The first line in this event handler is
while (dataSets.Count < count) { Thread.Sleep(100); }
//dataSets is a Dictionary<string, DataSet>
where count is the total amount of DataSets that are expected to be returned. My issue seems to be that dataSets.Count seems to become == to count before all of the DataSets are populated.
Here is my full code (Unhelpful/Sensitive information removed)
var hostThread = new BackgroundWorker();
hostThread.RunWorkerCompleted += new RunWorkerCompletedEventHandler(queryWorker_RunWorkerCompleted);
hostThread.DoWork += (send, even) =>
{
foreach (var cs in _connectionStrings)
{
var queryThread = new BackgroundWorker();
queryThread.DoWork += (se, eve) =>
{
var set = DataHandlers.TryGetDataSet(_query, cs, domain, username, pass);
dataSets.Add(((DataRow)set.Tables[0].Rows[0]).ItemArray[0].ToString(), set);
};
queryThread.RunWorkerAsync();
}
};
hostThread.RunWorkerAsync();
The RunWorkerCompleted :
var bw = new BackgroundWorker();
bw.DoWork += (s, ev) =>
{
//Waiting for all DataSets to get populated
while (dataSets.Count < count) { Thread.Sleep(100); }
//Thread.Sleep(5000); If I add this, everything works fine, but when I start running more queries in each query thread this needs to be increased.
this.Invoke((MethodInvoker)delegate()
{
this.Cursor = Cursors.Default;
this.Hide();
foreach (var set in dataSets)
{
if (set == null)
break;
//THIS BLOCK IS NEVER HIT IF I LEAVE OUT THE FIVE SECOND SLEEP
var workflowList = new List<string>();
foreach (var row in set.Value.Tables[0].Rows)
{
workflowList.Add(((DataRow)row).ItemArray[_licensed ? 1 : 0].ToString());
}
((MainForm)this.OwnedForms[0]).ClientWorkflows = new KeyValuePair<string, List<string>>(set.Key, workflowList);
}
//This gets hit before setting properties on a child form because it still thinks there are no DataSets in the dataSets dictionary
((MainForm)this.OwnedForms[0]).ShowDialog();
this.Close();
});
};
bw.RunWorkerAsync();
So as I stated in the comments in the code - I know that at some point the DataSets will be valid as long as I add a long enough sleep after the while loop. So what would be the best way to tell when all of the query threads are actually completed within the host thread completed event handler?
EDIT: Per #ndd this is what I ended up using.
var queryTasks = new List<Task>();
var parentTask = Task.Factory.StartNew(() =>
{
foreach (var cs in appConfigStrings)
{
queryTasks.Add(Task.Factory.StartNew(() => GetDataSets(mainForm, cs.Key, cs.Value)));
}
var array = queryTasks.ToArray();
Task.WaitAll(array);
});
parentTask.ContinueWith((t) =>
{
this.Invoke((MethodInvoker)delegate()
{
this.Cursor = Cursors.Default;
this.Hide();
foreach (var set in dataSets)
{
var workflowList = new List<string>();
foreach (var row in set.Value.Tables[0].Rows)
{
workflowList.Add(((DataRow)row).ItemArray[_licensed ? 1 : 0].ToString());
}
((MainForm)this.OwnedForms[0]).ClientWorkflows = new KeyValuePair<string, List<string>>(set.Key, workflowList);
}
((MainForm)this.OwnedForms[0]).ShowDialog();
this.Close();
});
});
Personally I am in never favor of Sleep as it is not predictable. If I had to use BackgroundWorker then I would likely go with IsBusy property to determine whether the BackgroundThread is done or not.
Sample code with TPL, please note this is just an example, in real world you may want to handle exceptions, pass cancellation token and other things :)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BGToTPL
{
class Program
{
static void Main(string[] args)
{
Task[] tasks = new Task[20];
//Parent task is starting 20 child tasks
var parentTask = Task.Run(() =>
{
Console.WriteLine("Parent threadid: " + System.Threading.Thread.CurrentThread.ManagedThreadId);
for (int i = 0; i < 20; i++)
{
tasks[i] = Task.Factory.StartNew(() =>
{
Console.WriteLine("Child threadid: " + System.Threading.Thread.CurrentThread.ManagedThreadId);
Task.Delay(15000);
});
}
});
parentTask.Wait();
Console.WriteLine("Parent task has started creating and running all the child tasks, now waiting for child tasks to be over.");
//Now wait for all the tasks to be done
Task.WaitAll(tasks);
Console.WriteLine("All the tasks are done");
Console.ReadKey();
}
}
}
And the output
How about something like this. — of course just if TPL is no option:
private readonly IList<BackgroundWorker> workers = new List<BackgroundWorker>();
private void Run()
{
var worker1 = new BackgroundWorker();
worker1.DoWork += (sender, args) => Thread.Sleep(1000);
worker1.RunWorkerCompleted += (sender, args) => this.CheckThreads();
var worker2 = new BackgroundWorker();
worker2.DoWork += (sender, args) => Thread.Sleep(1000);
worker2.RunWorkerCompleted += (sender, args) => this.CheckThreads();
lock (this.workers)
{
this.workers.Add(worker1);
this.workers.Add(worker2);
}
worker1.RunWorkerAsync();
worker2.RunWorkerAsync();
}
private void CheckThreads()
{
lock (this.workers)
{
if (this.workers.All(w => !w.IsBusy))
{
Console.WriteLine("All workers completed");
}
}
}

C# infinitive task loop using Task<> class + cancellation

I`m trying to make a small class for the multithreading usage in my WinForm projects.
Tried Threads(problems with UI), Backgroundworker(smth went wrong with UI too, just leave it now:)), now trying to do it with Task class. But now, can`t understand, how to make an infinitive loop and a cancelling method (in class) for all running tasks.
Examples i found is to be used in 1 method.
So, here is a structure & code of currently working part (Worker.css and methonds used in WinForm code).
Worker.css
class Worker
{
public static int threadCount { get; set; }
public void doWork(ParameterizedThreadStart method)
{
Task[] tasks = Enumerable.Range(0, 4).Select(i => Task.Factory.StartNew(() => method(i))).ToArray();
}
}
usage on
Form1.cs
private void Start_btn_Click(object sender, EventArgs e)
{
Worker.threadCount = 1; //actually it doesn`t using now, number of tasks is declared in class temporaly
Worker worker = new Worker();
worker.doWork(Job);
string logString_1 = string.Format("Starting {0} threads...", Worker.threadCount);
log(logString_1);
}
public static int j = 0;
private void Job(object sender)
{
Worker worker = new Worker();
Random r = new Random();
log("Thread "+Thread.CurrentThread.ManagedThreadId +" is working...");
for (int i = 0; i < 5; i++)
{
j++;
log("J==" + j);
if (j == 50)
{
//worker.Stop();
log("STOP");
}
}
Thread.Sleep(r.Next(500, 1000));
}
So, it run an example 4 threads, they executed, i got J==20 in my log, it`s ok.
My question is, how to implement infinitive loop for the tasks, created by Worker.doWork() method.
And also to make a .Stop() method for the Worker class (which should just stop all tasks when called). As i understand it`s related questions, so i put it in 1.
I tryed some solutions, but all of them based on the CancellationToken usage, but i have to create this element only inside of the Worker.doWork() method, so i can`t use the same token to create a Worker.Stop() method.
Someone can help? threads amount range i have to use in this software is about 5-200 threads.
using J computation is just an example of the the easy condition used to stop a software work(stop of tasks/threads).
In real, stop conditions is mostly like Queue<> is finished, or List<> elements is empty(finished).
Finally, get it works.
class Worker
{
public static int threadCount { get; set; }
Task[] tasks;
//ex data
public static string exception;
static CancellationTokenSource wtoken = new CancellationTokenSource();
CancellationToken cancellationToken = wtoken.Token;
public void doWork(ParameterizedThreadStart method)
{
try
{
tasks = Enumerable.Range(0, 4).Select(i => Task.Factory.StartNew(() =>
{
while (!cancellationToken.IsCancellationRequested)
{
method(i);
}
}, cancellationToken)).ToArray();
}
catch (Exception ex) { exception = ex.Message; }
}
public void HardStop()
{
try
{
using (wtoken)
{
wtoken.Cancel();
}
wtoken = null;
tasks = null;
}
catch (Exception ex) { exception = ex.Message; }
}
}
But if i`m using this method to quit cancellationToken.ThrowIfCancellationRequested();
Get a error:
when Job() method reach J == 50, and worker.HardStop() function called, program window crashes and i get and exception "OparetionCanceledException was unhandled by user code"
on this string
cancellationToken.ThrowIfCancellationRequested();
so, whats wrong? i`m already put it in try{} catch(){}
as i understood, just some boolean properties should be changed in Task (Task.IsCancelled == false, Task.IsFaulted == true) on wtoken.Cancel();
I'd avoid all of the mucking around with tasks and use Microsoft's Reactive Framework (NuGet "Rx-Main") for this.
Here's how:
var r = new Random();
var query =
Observable
.Range(0, 4, Scheduler.Default)
.Select(i =>
Observable
.Generate(0, x => true, x => x, x => x,
x => TimeSpan.FromMilliseconds(r.Next(500, 1000)),
Scheduler.Default)
.Select(x => i))
.Merge();
var subscription =
query
.Subscribe(i => method(i));
And when you want to cancel the calls to method just do this:
subscription.Dispose();
I've tested this and it works like a treat.
If I wrap this up in your worker class then it looks like this:
class Worker
{
private Random _r = new Random();
private IDisposable _subscription = null;
public void doWork()
{
_subscription =
Observable
.Range(0, 4, Scheduler.Default)
.Select(n =>
Observable
.Generate(
0, x => true, x => x, x => x,
x => TimeSpan.FromMilliseconds(_r.Next(500, 1000)),
Scheduler.Default)
.Select(x => n))
.Merge()
.Subscribe(i => method(i));
}
public void HardStop()
{
_subscription.Dispose();
}
}

Waiting on multiple background threads

I want know when all thread has been finished in a multithread program
without something like pooling
while(!allThreadFinished){
thread.sleep(100);
}
The solution should be used Monitor but i can't how can i approve that it's correct.
since the "SomeMethod" in the following code using network, it consume times.
public object SomeMethod(string input);
public object[] MultiThreadMethod(string[] inputs) {
var result = new object[inputs.Count()];
int i = 0;
foreach (var item in inputs) {
BackgroundWorker work = new BackgroundWorker();
work.DoWork += (sender, doWorkEventArgs) => { doWorkEventArgs.Result = SomeMethod(item); };
work.RunWorkerCompleted += (sender, runWorkerCompletedEventArgs) => {
result[i] = runWorkerCompletedEventArgs.Result;
};
i++;
work.RunWorkerAsync();
}
/////////////////////////////////////////////////////////////
//**wait while all thread has been completed**
/////////////////////////////////////////////////////////////
return result;
}
Try using the TPL http://msdn.microsoft.com/en-us/library/dd460717.aspx.
List<Task> tasks = new List<Task>();
Task t1 = new Task(() =>
{
// Do something here...
});
t1.Start();
tasks.Add(t1);
Task t2 = new Task(() =>
{
// Do something here...
});
t2.Start();
tasks.Add(t2);
Task.WaitAll(tasks.ToArray());
You can use TPL to do the same, you will avoid using Thread.Sleep(), and it will be much clearer. Check this out: http://msdn.microsoft.com/en-us/library/dd537610.aspx
Your example with TPL would look like this (untested code):
private ConcurrentBag<object> _results;
public object[] MultiThreadMethod(string[] inputs)
{
_results = new ConcurrentBag<object>();
var tasks = new Task[inputs.Length];
for (int i = 0; i < inputs.Length; i++)
{
tasks[i] = Task.Factory.StartNew(() => DoWork(inputs[i]));
}
Task.WaitAll(tasks);
return _results.ToArray();
}
private void DoWork(string item)
{
_results.Add(SomeMethod(item));
}
EDIT: Without ConcurrentBag:
public object[] MultiThreadMethod(string[] inputs)
{
var tasks = new Task<object>[inputs.Length];
for (int i = 0; i < inputs.Length; i++)
{
tasks[i] = Task<object>.Factory.StartNew(() => DoWork(inputs[i]));
}
Task.WaitAll(tasks);
return tasks.Select(task => task.Result).ToArray();
}
private object DoWork(string item)
{
return SomeMethod(item);
}
Hook the RunWorkerCompleted event on the BackgroundWorker. It will fire when the work is done.
A complete example of how to use the BackgroundWorker properly can be found here.
http://msdn.microsoft.com/en-us/library/dd537608.aspx
// Sequential version
foreach (var item in sourceCollection)
Process(item);
// Parallel equivalent
Parallel.ForEach(sourceCollection, item => Process(item));

Problem with Invoke to parallelize foreach

I have a problem with using System.Threading.Tasks.Parallel.ForEach. The body foreach progressBar want to update.
But Invoke method sometimes freeze.
I attach the code to the form which is prograssbar and Buton.
private void button1_Click(object sender, EventArgs e)
{
DateTime start = DateTime.Now;
pforeach();
Text = (DateTime.Now - start).ToString();
}
private void pforeach()
{
int[] intArray = new int[60];
int totalcount = intArray.Length;
object lck = new object();
System.Threading.Tasks.Parallel.ForEach<int, int>(intArray,
() => 0,
(x, loop, count) =>
{
int value = 0;
System.Threading.Thread.Sleep(100);
count++;
value = (int)(100f / (float)totalcount * (float)count);
Set(value);
return count;
},
(x) =>
{
});
}
private void Set(int i)
{
if (this.InvokeRequired)
{
var result = Invoke(new Action<int>(Set), i);
}
else
progressBar1.Value = i;
}
Sometimes it passes without a problem, but usually it freeze on
var result = Invoke (new Action <int> (Set), i).
Try to kick me in the problem.
Thank you.
Your problem is that Invoke (and queueing a Task to the UI TaskScheduler) both require the UI thread to be processing its message loop. However, it is not. It is still waiting for the Parallel.ForEach loop to complete. This is why you see a deadlock.
If you want the Parallel.ForEach to run without blocking the UI thread, wrap it into a Task, as such:
private TaskScheduler ui;
private void button1_Click(object sender, EventArgs e)
{
ui = TaskScheduler.FromCurrentSynchronizationContext();
DateTime start = DateTime.Now;
Task.Factory.StartNew(pforeach)
.ContinueWith(task =>
{
task.Wait(); // Ensure errors are propogated to the UI thread.
Text = (DateTime.Now - start).ToString();
}, ui);
}
private void pforeach()
{
int[] intArray = new int[60];
int totalcount = intArray.Length;
object lck = new object();
System.Threading.Tasks.Parallel.ForEach<int, int>(intArray,
() => 0,
(x, loop, count) =>
{
int value = 0;
System.Threading.Thread.Sleep(100);
count++;
value = (int)(100f / (float)totalcount * (float)count);
Task.Factory.StartNew(
() => Set(value),
CancellationToken.None,
TaskCreationOptions.None,
ui).Wait();
return count;
},
(x) =>
{
});
}
private void Set(int i)
{
progressBar1.Value = i;
}
I was looking at how I did this and this change may help you:
In my constructor I have this line:
TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
Then I do this:
private void changeProgressBar()
{
(new Task(() =>
{
mainProgressBar.Value++;
mainProgressTextField.Text = mainProgressBar.Value + " of " + mainProgressBar.Maximum;
})).Start(uiScheduler);
}
This gets rid of needing to use Invoke, and if you use the Task method then it may solve your problem.
I think these were all in System.Threading.Tasks;

Categories