How can i kill or stop backgroundworker? - c#

To load several large files quickly, I launched backgroundworkers as the number of files.
Each backgroundworker needs long time to load its file respectively. While they load their files, I'd like to stop all loading. I understand backgroundworker.CancelAsync() sends cancellation message to the thread, but the thread has no time to accept the message. Because each thread is loading just one file and there is no loop operation to check cancellation. In this case, how can I stop these backgroundworkers?
Let me show my codes here.
//main thread calls 50 child threads.
private List<BackgroundWorker> bgws = new List<BackgroundWorker>();
private bool ChildThreadCompleted;
private void MainThread_DoWork(object sender, DoWorkEventArgs e)
{
// 50 sub threads will be started here
for (int i=1; i<=50; i++)
{
if (mainThread.CancellationPending) return;
BackgroundWorker childThread = new BackgroundWorker();
childThread.WorkerSupportsCancellation = true;
childThread.DoWork += ChildThread_DoWork;
childThread.RunWorkerCompleted += ChildThread_RunWorkerCompleted;
bgws.Add(childThread);
childThread.RunWorkerAsync(i);
}
while (!ChildThreadCompleted)
{
if (mainThread.CancellationPending)
{
foreach (BackgroundWorker thread in bgws)
if (thread.IsBusy) thread.CancelAsync();
}
Application.DoEvents();
}
}
private void ChildThread_DoWork(object sender, DoWorkEventArgs e)
{
int arg = Convert.ToInt32(e.Argument);
System.Threading.Thread.Sleep(1000);
BackgroundWorker thread = (BackgroundWorker)sender;
if (thread.CancellationPending) return;
// In case of loading the image no longer makes sense, I'd like to stop.
// At this point, i can't stop this process.
//loading large file here. Just one image file for example. <= this takes one or more seconds
e.Result = arg;
}
private void ChildThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
BackgroundWorker thread = sender as BackgroundWorker;
bgws.Remove(thread);
if (bgws.Count == 0) ChildThreadCompleted = true;
}

Short version
BGW can't do that, not without complex coding. ActionBlock was purpose-built to handle a stream of inputs with cancellation support.
I use the dataflow classes to find, download and proccess thousands of air ticket records every 15 minutes.
Long Version
BackgroundWorker is obsolete, fully replaced by TPL classes like tasks, CancellationToken, IProgress etc.
This particular problem though is best addressed by a higher-level class, ActionBlock.
ActionBlock and the other classes in the TPL Dataflow namespace allow you to create a pipeline of blocks similar to a Powershell pipeline.
Each block runs on its own task, receives an input and passes an output to the next block. You can even specify that one block can process multiple inputs by using multiple tasks.
ActionBlock doesn't produce any output, it only processes inputs. Like most blocks, it has an input buffer and supports cancellation.
A file processing block could look like this. :
var block=new ActionBlock<string>(file => SomeSlowFileProcessing(file));
var files = Directory.EnumerateFiles(someFolder,somePattern);
//Post all files
foreach(file in files)
{
//Post doesn't block
block.Post(file);
}
When we are done using the block, we should tell it we're finished :
block.Complete();
And await asynchronously until all leftover files are processed :
await block.Completion;
You can instruct the block to process multiple messages in parallel by specifying the maximum number of concurrent tasks :
var options = new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = 20
};
var block=new ActionBlock<string>(file => SomeSlowFileProcessing(file), options);
Starting 100 threads to process 100 files will probably result in the threads blocking each other. By limiting the number of concurrent tasks you ensure all the CPUs can perform useful work.
You can also stop the block. One way is to "nuke" it by calling the Fault() method :
block.Fault();
try
{
await block.Completion;
}
catch(Exception exc)
{
...
}
This will discard everything left into the input buffer and propagate an exception to the next block in the pipeline. It's as if the block's method threw an exception. In this case there's no other block and await block.Completion; will throw.
Another, more cooperative way is to use a CancellationTokenSource to cancel the block and signal the worker method that it should cancel.
A CancellationTokenSource is a class that can be used to signal cancellation to any task, thread or other code. It does that by providing a CancellationToken whose IsCancellationRequested property becomes true when someone calls Cancel() on the CTS, or its timeout interval expires.
This way, you can provide a timeout feature to your block by creating a CTS with a timeout period :
var cts=new CancellationTokenSource(60000); //Timeout in 1 minute
var options = new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = 20,
CancellationToken=cts.Token
};
var block=new ActionBlock<string>(file => SomeSlowFileProcessing(file), options);
//.....
try
{
await block.Completion;
}
catch (OperationCanceledException)
{
Console.WriteLine("Timed out!");
}
A button event can be used to signal cancellation if the CTS is stored in a field :
CancellationTokenSource _cts;
ActionBlock _block;
public void Start_Click(object sender, EventArgs args)
{
//Make sure both the CTS and block are created before setting the fields
var cts=new CancellationTokenSource(60000); //Timeout in 1 minute
var token=cts.Token;
var options = new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = 20,
CancellationToken=token
};
var block=new ActionBlock<string>(file => SomeSlowFileProcessing(file,token),
options);
//Once preparation is over ...
_cts=cts;
_block=block;
//Start posting files
...
}
public async void Cancel_Click(object sender, EventArgs args)
{
lblStatus.Text = "Cancelling";
_cts.Cancel();
try
{
await _block.Completion;
}
lblStatus.Text = "Cancelled!";
}
Loading large files with cancellation
Asynchronous file operations also accept a cancellation token, eg FileStream.ReadAsync has an overload that accepts a CancellationToken
This means that the worker method can be cancelled if it's converted to an async method, eg
async Task MySlowMethod(string fileName,CancellationToken token)
{
try
{
using (FileStream SourceStream = File.Open(filename, FileMode.Open))
{
var data = new byte[SourceStream.Length];
await SourceStream.ReadAsync(data, 0, (int)SourceStream.Length,token);
// Use the data
}
}

Related

Replace 'BackgroundWorker' With 'Thread '

I want to replace BackgroundWorker in my winform application with a Thread.
The goal is do the the jobs in a new thread other than UI-thread & prevent program hang during run.
So i did this :
private void radBtn_start_Click(object sender, EventArgs e)
{
try
{
string thread_name = "trd_" + rnd.Next(99000, 10000000).ToString();
Thread thread = new Thread(new ThreadStart(Thread_Method));
thread.Name = thread_name;
thread.Start();
}
catch (System.Exception ex)
{
MessageBox.Show("Error in radBtn_start_Click() Is : " + ex.ToString());
}
}
public void Thread_Method()
{
...Some Jobs
Thread.Sleep(20000);
...Some Jobs After Delay
Thread.Sleep(20000);
...Some Jobs After Delay
this.Invoke(new MethodInvoker(delegate
{
radTextBoxControl1.Text += DateTime.Now.ToString() + " : We are at end of search( " + radDropDownList1.SelectedItem.Tag + " ) = -1" + Environment.NewLine;
}));
}
But after running these codes UI hangs during sleep.
What is the correct codes for my purpose?
You don't have to create a new Thread, your process already has a pool of threads anxiously waiting to do something for you
Usually the threads in the thread pool are used when you use async-await. However, you can also use them for heavy calculations
My advice is to make your thread_method async. This has the advantage, that whenever your thread_method has to wait idly for another process to finish, like writing data to a file, fetching items from a database, or reading information from the internet, the thread is available for the thread pool to do other tasks.
If you are not familiar with async-await: this interview with Eric Lippert really helped me to understand what happens when you use async-await. Search somewhere in the middle for async-await.
One of the nice things about async-await, is that the executing thread has the same "context" as the UI-thread, so this thread can access UI-elements. No need to check for InvokeRequired or to call Invoke.
To make your ThreadMethod async:
declare it async
instead of TResults return Task<TResult>; instead of void return Task
only exception: async event handlers return void
whenever you call other methods that have an async version, call this async version, start awaiting when you need the results of the async task.
public async Task FetchCustomerAddress(int customerId)
{
// fetch the customer address from the database:
using (var dbContext = new OrderDbContext(...))
{
return await dbContext.Customers
.Where(customer => customer.Id == customerId)
.Select(customer => new Address
{
Name = customer.Name,
Street = customer.Street,
... // etc
})
.FirstOrDefaultAsync();
}
}
public async Task CreateCustomerOrder(
int customerId, IEnumerable orderLines)
{
// start reading the customer Address
var taskReadCustomerAddress = this.FetchCustomerAddress(customerId);
// meanwhile create the order
CustomerOrder order = new CustomerOrder();
foreach (var orderLine in orderLines)
{
order.OrderLines.Add(orderLine);
}
order.CalculateTotal();
// now you need the address of the customer: await:
Address customerAddress = await taskReadCustomerAddress;
order.Address = customerAddress;
return order;
}
Sometimes you don't have to wait idly for another process to finish, but you need to do some heavy calculations, and still keep your UI-thread responsive. In older applications you would use the BackgroundWorker for this, in newer applications you use Task.StartNew
For instance, you have a button, and a menu item that both will start some heavy calculations. Just like when using the backgroundworker you want to show some progress. While doing the calculations, both the menu item and the button need to be disable.
public async Task PrintCustomerOrdersAsync(
ICollection<CustomerOrderInformation> customerOrders)
{
// while creating the customer orders: disable the button and the menu items
this.buttonPrintOrders.Enabled = false;
this.menuItemCreateOrderLines.Enabled = false;
// show the progress bar
this.ProgressBarCalculating.MinValue = 0;
this.ProgressBarCalculating.MaxValue = customers.Count;
this.ProgressBarCalculating.Value = 0;
this.ProgressBarCalculating.Visible = true;
List<Task<PrintJob>> printJobs = new List<Task<PrintJob>>();
foreach (CustomerOrderInformation orderInformation in customerOrders)
{
// instead of BackGroundworker raise event, you can access the UI items yourself
CustomerOrder order = this.CreateCustomerOrder(orderInformation.CustomerId,
orderInformation.OrderLines);
this.ProgressBarCalculating.Value +=1;
// print the Order, do not await until printing finished, create next order
printJobs.Add(this.Print(order));
}
// all orders created and sent to the printer. await until all print jobs complete:
await Task.WhenAll(printJobs);
// cleanup:
this.buttonPrintOrders.Enabled = true;
this.menuItemCreateOrderLines.Enabled = true;
this.ProgressBarCalculating.Visible = false;
}
By the way: in a proper design, you would separate the enabling / disabling the items from the actual processing:
public async Task PrintCustomerOrdersAsync(ICollection<CustomerOrderInformation> customerOrders)
{
this.ShowBusyPrintingOrders(customerOrders.Count);
await this.PrintOrdersAsync(customerOrders);
this.HideBusyPrintingOrders();
}
Now to start printing the orders when a button is pressed, there are two possibilities:
If the process is mostly waiting for others: async event handler
If there are really heavy calculations (longer than a second?): start a task that does the calculations
No heavy calculations:
// async event handler has void return value!
private async void ButtonPrintOrdersClickedAsync(object sender, ...)
{
var orderInformations = this.GetOrderInformations();
await PrintCustomerOrdersAsync(orderInformations);
}
Because I don't have anything other useful to do, I await immediately
Heavy calculations: start a separate task:
private async Task ButtonCalculateClickedAsync(object sender, ...)
{
var calculationTask = Task.Run(() => this.DoHeavyCalculations(this.textBox1.Text);
// because you didn't await, you are free to do something else,
// for instance show progress:
while (!calculationTask.Complete)
{
// await one second; UI is responsive!
await Task.Delay(TimeSpan.FromSeconds(1));
this.ProgressBar.Value += 1;
}
}
Be aware: using these methods, you can't stop the process. So you are in trouble if the operator wants to close the application while you are still printing.
Just like your background thread, every method that supports cancellation should regularly check if cancellation is requested. The advantage is, that this checking is also done in the .NET methods that support cancellation, like reading database information, writing a file, etc. The backgroundWorker couldn't cancel writing to a file.
For this we have the CancellationTokenSource
private CancellationTokenSource cancellationTokenSource;
private Task taskPrintOrders;
public async Task PrintCustomerOrdersAsync(ICollection<CustomerOrderInformation> customerOrders)
{
this.ShowBusyPrintingOrders(customerOrders.Count);
using (this.cancellactionTokenSource = new CancellationTokenSource())
{
taskPrintOrders = this.PrintOrdersAsync(customerOrders, this.cancellationTokenSource.Token);
await taskPrintOrders;
this.HideBusyPrintingOrders();
}
private void CancelPrinting()
{
this.cancellationTokenSource?.Cancel();
}
If you want to cancel and wait until finished, for instance when closing the form:
private bool TaskStillRunning => this.TaskPrinting != null && !this.TaskPrinting.Complete;
private async void OnFormClosing(object sender, ...)
{
if (this.TaskStillRunning)
{
bool canClose = this.AskIfCanClose();
if (!canClose)
eventArgs.Cancel = true;
else
{
// continue closing: stop the task, and wait until stopped
this.CancelPrinting();
await this.taskPrintOrders;
}
}
}
This will work in separate thread without hanging your UI.
Use new Thread
new Thread(delegate()
{
Thread_Method();
}).Start();
or Task.run
Task.Run(() =>
{
Thread_Method();
});

Managing task cancellation and completion on a concurrent thread

[ This question needs to be reimagined. One of my thread queues MUST run on an STA thread, and the code below does not accommodate that. In particular it seems Task<> chooses its own thread and that just is not going to work for me. ]
I have a task queue (BlockingCollection) that I'm running through on a dedicated thread. That queue receives a series of Task<> objects that it runs sequentially within that thread via a while loop.
I need a means of Cancelling that series of tasks, and a means of knowing that the tasks are all complete. I have not been able to figure out how to do this.
Here's a fragment of my queuing class. ProcessQueue is run on a separate thread from main. QueueJob calls occur on the main thread.
using Job = Tuple<Task<bool>, string>;
public class JobProcessor
{
private readonly BlockingCollection<Job> m_queue = new BlockingCollection<Job>();
volatile bool cancel_queue = false;
private bool ProcessQueue()
{
while (true)
{
if (m_queue.IsAddingCompleted)
break;
Job tuple;
if (!m_queue.TryTake(out tuple, Timeout.Infinite))
break;
var task = tuple.Item1;
var taskName = tuple.Item2;
try
{
Console.WriteLine("Task {0}::{1} starting", this.name, taskName);
task.RunSynchronously();
Console.WriteLine("Task {0}::{1} completed", this.name, taskName);
}
catch (Exception e)
{
string message = e.Message;
}
if (cancel_queue) // CANCEL BY ERASING TASKS AND NOT RUNNING.
{
while (m_queue.TryTake(out tuple))
{
}
}
} // while(true)
return true;
}
public Task<bool> QueueJob(Func<bool> input)
{
var task = new Task<bool>(input);
try
{
m_queue.Add(Tuple.Create(task, input.Method.Name));
}
catch (InvalidOperationException)
{
Task<bool> dummy = new Task<bool>(() => false);
dummy.Start();
return dummy;
}
return task;
}
Here are the functions that trouble me:
public void ClearQueue()
{
cancel_queue = true;
// wait for queue to become empty. HOW?
cancel_queue = false;
}
public void WaitForCompletion()
{
// wait for all tasks to be completed.
// not sufficient to wait for empty queue because the last task
// must also execute and finish. HOW?
}
}
Here is some usage:
class SomeClass
{
void Test()
{
JobProcessor jp = new JobProcessor();
// launch Processor loop on separate thread... code not shown.
// send a bunch of jobs via QueueJob... code not show.
// launch dialog... code not shown.
if (dialog_result == Result.Cancel)
jp.ClearQueue();
if (dialog_result == Result.Proceed)
jp.WaitForCompletion();
}
}
The idea is after the work is completed or cancelled, new work may be posted. In general though, new work may come in asynchronously. WaitForCompletion might in fact be "when all work is done, inform the user and then do other stuff", so it doesn't strictly have to be a synchronous function call like above, but I can't figure how to make these happen.
(One further complication, I expect to have several queues that interact. While I am careful to keep things parallelized in a way to prevent deadlocks, I am not confident what happens when cancellation is introduced into the mix, but this is probably beyond scope for this question.)
WaitForCompletion() sounds easy enough. Create a semaphore or event, create a task whose only action is to signal the semaphore, queue up the task, wait on the semaphore.
When the thread finishes the last 'real' task, the semaphore task will be run and so the thread that called WaitForCompletion will become ready/running:)
Would not a similar approach work for cancellation? Have a very high priority thread that you create/signal that drains the queue of all pending jobs, disposing them, queueing up the semaphore task and waiting for the 'last task done' signal?

parallel check open port ip from file

I want to check the open port in a group of ip . I do not want to check an ip behind a title sequentially. But I want it in parallel so that the user determines the number of threads. The number of ip is divided into threads :
private async void button3_Click(object sender, EventArgs e)
{
await Task.Run(() =>
{
var lines = File.ReadAllLines("ip.txt");
int cc = (lines.Length) / (int.Parse(thread.Text));
if (lines.Length % int.Parse(thread.Text) == 0)
{
for (int s = 0; s < lines.Length; s = s + cc)
{
Parallel.For(0, 1, a =>
{
checkopen(s, (s + cc));
});
}
}
else
{
MessageBox.Show("enter true thread num");
}
});
}
this to check open port :
void checkopen(int first,int last)
{
int port = Convert.ToInt32(portnum.Text);
var lines = File.ReadAllLines("ip.txt");
for (int i = first; i < last; ++i)
{
var line = lines[i];
using (TcpClient tcpClient = new TcpClient())
{
try
{
tcpClient.Connect(line, port);
this.Invoke(new Action(() =>
{
listBox1.Items.Add(line); // open port
}));
}
catch (Exception)
{
this.Invoke(new Action(() =>
{
listBox2.Items.Add(line); //close port
}));
}
}
}
}
I see this problem every day.
There is no point putting IO bound operations in Parallel.For, it's not designed for IO work, or the async pattern (and trust me, that's what you want).
Why do we want the async await pattern?
Because it designed to give the threads back when it's awaiting an IO completion port or awaitable workload.
When you run IO work in Parallel.For/Parallel.ForEach like this, the Task Scheduler just won't give you threads to block, it uses all sort of heuristics to work out how many threads you should have, and it takes a dim view of it.
So what should we use?
The async and await pattern.
Why?
Because we can let IO be IO, the system creates and IO completion port, .Net gives the thread back to the threadpool until the Completion port calls back and the method continues.
So, there are many options for this. But first and foremost await the awaitable async methods of the libraries you are using.
From here you can either create a lists of tasks and use something like an awaitable SemaphoreSlim to limit concurrency and a WhenAll.
Or you could use something like an ActionBlock out of TPL Dataflow, which is designed to work with both CPU and IO bound workloads.
The real world benefits can't be understated. Your Parallel.For approach will just run a handful of thread and block them. An async version you'll be able to run 100s simultaneously.
Dataflow example
You can get the Nuget here
public async Task DoWorkLoads(List<WorkLoad> workloads)
{
var options = new ExecutionDataflowBlockOptions
{
// add pepper and salt to taste
MaxDegreeOfParallelism = 100,
EnsureOrdered = false
};
// create an action block
var block = new ActionBlock<WorkLoad>(MyMethodAsync, options);
// Queue them up
foreach (var workLoad in workloads)
block.Post(workLoad );
// wait for them to finish
block.Complete();
await block.Completion;
}
...
// Notice we are using the async / await pattern
public async Task MyMethodAsync(WorkLoad workLoad)
{
try
{
Console.WriteLine("Doing some IO work async);
await DoIoWorkAsync;
}
catch (Exception)
{
// probably best to add some error checking some how
}
}

C#: CancellationToken doesn't cancel blocking method

.NET 4.5.1: It appears, I can't cancel a blocking method running inside a task using the CancellationTokenSource built-in timeout.
class Program
{
static void Main(string[] args)
{
var cts = new System.Threading.CancellationTokenSource();
System.Console.CancelKeyPress += (s, e) =>
{
e.Cancel = true;
cts.Cancel();
};
MainAsync(args, cts.Token).Wait();
}
// MainAsync from http://stackoverflow.com/questions/9208921/async-on-main-method-of-console-app
static async Task MainAsync(string[] args, System.Threading.CancellationToken token)
{
Console.WriteLine("Starting MainAsync");
var cts = new System.Threading.CancellationTokenSource(3000);
var task = Task.Factory.StartNew(() =>
{
Console.WriteLine("Starting task...");
var t = new System.Net.Sockets.TcpClient();
var buffer = new byte[t.ReceiveBufferSize];
t.Connect(new System.Net.IPEndPoint(System.Net.IPAddress.Parse("127.0.0.1"), 1337));
Console.WriteLine("Recieving...");
t.Client.Receive(buffer);
Console.WriteLine("Finished Recieving...");
return true;
}, cts.Token);
var success = await task;
Console.WriteLine("Did the task complete succesfuly?", success);
}
}
The output from the above Short, Self Contained, Correct Example (I hope it's correct) is:
Starting MainAsync
Starting task...
Recieving...
Why does the task doesn't cancel, no exception is thrown?
As I state on my blog, "You keep using that CancellationToken there. I do not think it means what you think it means."
In particular, the CancellationToken passed to StartNew will only cancel the starting of the delegate. If you want the delegate itself to support cancellation, then the delegate itself will have to observe the CancellationToken.
I am not sure but I guess you are confusing "requesting a cancellation" with "terminating or aborting a thread/task".
These are two completly different things. According to the description about the Canellation in Managerd Threads the provided functionality enables you to send something like a signal, indicating, that the operation in progress shall be stopped.
How and if you react on that signal is - as a programmer - up to you.
In your example you've started a new task
var task = Task.Factory.StartNew(() =>
{
Console.WriteLine("Starting task...");
var t = new System.Net.Sockets.TcpClient();
var buffer = new byte[t.ReceiveBufferSize];
t.Connect(new System.Net.IPEndPoint(System.Net.IPAddress.Parse("127.0.0.1"), 1337));
Console.WriteLine("Recieving...");
t.Client.Receive(buffer);
Console.WriteLine("Finished Recieving...");
return true;
}, cts.Token);
which does not handle the cancellation nor is it suitable to do so.
Canellation would be used e.g. if you want to break out of a loop with many iterations - therefore you would check in each iteration whether the CancellationToken.IsCancellationRequested has been set to true or not.
If so, you can react accordingly.
What you want is to abort the thread that's behind the current task which is in my opinion only possible by creating a new instance of the Thread class for yourself and handle the abort accordingly.

Stop my task and all my waiting task

i have an application who take all the added files from my Listbox and play this files:
IEnumerable<string> source
public void play()
{
Task.Factory.StartNew(() =>
{
Parallel.ForEach(source,
new ParallelOptions
{
MaxDegreeOfParallelism = 1 //limit number of parallel threads
},
file =>
{
//each file process via another class
});
}).ContinueWith(
t =>
{
OnFinishPlayEvent();
}
, TaskScheduler.FromCurrentSynchronizationContext() //to ContinueWith (update UI) from UI thread
);
}
my processing file can be stop via my class property but if i want to stop all the files
that waiting how can i do it ?
You need to design your routines to accept a CancellationToken, and then trigger a CancellationTokenSource.Cancel().
This will allow you to provide a mechanism to cooperatively cancel your work.
For details, see Cancellation in Managed Threads and Task Cancellation on MSDN.
If you want to stop a parallel loop, use an instance of the ParallelLoopState class. To cancel a task, you want to use a CancellationToken. Since you are embedding your parallel loop inside a task, you can simply pass a cancellation token into the task. Bear in mind, this will throw an OperationCanceledException you will have to catch, if you choose to wait on your task(s).
For example, and for the sake of argument, we'll assume that something else will call a delegate inside your class that will set the cancellation token.
CancellationTokenSource _tokenSource = new CancellationTokenSource();
//Let's assume this is set as the delegate to some other event
//that requests cancellation of your task
void Cancel(object sender, EventArgs e)
{
_tokenSource.Cancel();
}
void DoSomething()
{
var task = Task.Factory.StartNew(() => {
// Your code here...
}, _tokenSource.Token);
try {
task.Wait();
}
catch (OperationCanceledException) {
//Carry on, logging that the task was canceled, if you like
}
catch (AggregateException ax) {
//Your task will throw an AggregateException if an unhandled exception is thrown
//from the worker. You will want to use this block to do whatever exception handling
//you do.
}
}
Bear in mind, there are better ways to do this (and I'm typing from memory here, so there could be some syntax errors and the like), but this should get you started.

Categories

Resources