Cancel request if taking to long to process - c#

Hello is this possible in c#:
If I have a loop say:
int x = 0;
for (int i = 0; i < 1000000; i++) {
x++;
}
And it takes more than 1 second to complete, is it possible to kill the code and move on?

Yes, if you have the loop running in a different thread, you can abort that thread from a different thread. This would effectively kill the code you're running, and would work fine in the simplified example you've given. The following code demonstrates how you might do this:
void Main()
{
double foo = 0;
var thread = new Thread(() => foo = GetFoo());
thread.Start();
string message;
if(thread.Join(1000))
{
message = foo.ToString();
}
else
{
message = "Process took too long";
thread.Abort();
}
message.Dump();
}
public double GetFoo() {
double a = RandomProvider.Next(2, 5);
while (a == 3) { RandomProvider.Next(2, 5);}
double b = RandomProvider.Next(2, 5);
double c = b /a;
double e = RandomProvider.Next(8, 11);
while (e == 9) { RandomProvider.Next(8,11); }
double f = b / e;
return f;
}
However, as you can see from Eric Lippert's comment (and others), aborting a thread is not very graceful (a.k.a. "pure evil"). If you were to have important things happening inside this loop, you could end up with data in an unstable state by forcing the thread abortion in the middle of the loop. So it is possible, but whether you want to use this approach will depend on what exactly you're doing in the loop.
So a better option would be to have your loops voluntarily decide to exit when they're told to (Updated 2015/11/5 to use newer TPL classes):
async void Main()
{
try
{
var cancelTokenSource = new CancellationTokenSource(TimeSpan.FromMilliseconds(1000));
var foo = await GetFooAsync(cancelTokenSource.Token);
Console.WriteLine(foo);
}
catch (OperationCanceledException e)
{
Console.WriteLine("Process took too long");
}
}
private Random RandomProvider = new Random();
public async Task<double> GetFooAsync(CancellationToken cancelToken) {
double a = RandomProvider.Next(2, 5);
while (a == 3)
{
cancelToken.ThrowIfCancellationRequested();
RandomProvider.Next(2, 5);
}
double b = RandomProvider.Next(2, 5);
double c = b /a;
double e = RandomProvider.Next(8, 11);
while (e == 9)
{
cancelToken.ThrowIfCancellationRequested();
RandomProvider.Next(8,11);
}
double f = b / e;
return f;
}
This gives GetFooAsync an opportunity to catch on to the fact that it's supposed to exit soon, and make sure it gets into a stable state before giving up the ghost.

If you control the code that needs to be shut down then write logic into it that enables it to be shut down cleanly from another thread.
If you do not control the code that needs to be shut down then there are two scenarios. First, it is hostile to you and actively resisting your attempts to shut it down. That is a bad situation to be in. Ideally you should run that code in another process, not another thread, and destroy the process. A hostile thread has lots of tricks it can do to keep you from shutting it down.
Second, if it is not hostile and it can't be shut down cleanly then either it is badly designed, or it is buggy. Fix it. If you can't fix it, run it in another process, just like it was hostile.
The last thing you should do is abort the thread. Thread aborts are pure evil and should only be done as a last resort. The right thing to do is to design the code so that it can be cancelled cleanly and quickly.
More thoughts:
http://blogs.msdn.com/b/ericlippert/archive/2010/02/22/should-i-specify-a-timeout.aspx
Alternatively, you could go with a single-threaded approach. Break the work up into small chunks where the last thing each chunk of work does is enqueues the next chunk of work onto a work queue. You then sit in a loop, pulling work out of the queue and executing it. To stop early, just clear the queue. No need to go with a multithreaded approach if you don't need to.

You can achieve this in a simple way without mucking around with threading:
int x = 0;
int startTime = Environment.TickCount;
for (int i = 0; i < 1000000; i++)
{
x++;
int currentTime = Environment.TickCount;
if ((currentTime - startTime) > 1000)
{
break;
}
}
You can replace Environment.TickCount with a DateTime call or System.Diagnostics.Stopwatch if you like.

You can use background worker, this class supports cancellation

If the problem is the number of iteration in the loop more than what you do inside the loop, then you can ask for save the time when the loop started, and see de diference betweeen each iteration ( or maybe %10, 20, 100) and cancel if the time you wanted to spend on that task is over.

Related

List of worker threads spawned by for loop is exceeding for-loop iterations

I am relatively green to proper threading, I have this, it's modified for simplicity but it is essentially the same thing:
//Global:
N=2
bool[] mySwitches;
//In my main:
mySwitches = new bool[N];
for (int i = 0; i < N; i++)
{
ThreadList.Add(new Thread(() => Worker(i)));
ThreadList[i].Start();
}
//Outside of main:
Private Void Worker(int num)
{
while(true)
{
if (mySwitches[num]) //error happes here because num is equal to N, how?
{
//do something
}
}
}
As shown above, somehow a worker thread gets a value of num=N, I expect it to only reach N-1.
I know that i will get incremented after the Worker is created, is i somehow getting passed by reference instead of value?
I tried to fix the issue by putting a test before my while loop to return if num=N, but even with this provision I get the same error. This leads me to believe that num is incremented somehow after the thread starts.
I fixed this issue by putting a Sleep(20) directly after ThreadList[i].Start(), but I don't really like using Sleep, and it's clear I don't know how this threading scenario actually works.
Can anyone shed any light on this?
i is captured by its reference. Change your code as
for (int i = 0; i < N; i++)
{
var thInx = i;
ThreadList.Add(new Thread(() => Worker(thInx)));
ThreadList[thInx].Start();
}
For more info: http://csharpindepth.com/articles/chapter5/closures.aspx

Issue with thread barrier - PulseAll not reaching all threads

I have a parallel algorithm which I have some barrier issues with. Before y'all scream "search" I can say I have looked at available posts and links, and I have followed the instructions for a barrier with Monitor.Wait and Monitor.PulseAll, but my issue is that all threads except the last one created (and initiated) is reached by the PulseAll from my main thread. Here are how the basic layout of the code is:
public static object signal = new object(); //This one is located as class variable, not in the method
public void RunAlgorithm(List<City> cities){
List<Thread> localThreads = new List<Thread>();
object[] temp = //some parameters here
for(int i = 0; i < numOfCitiesToCheck; i++){
Thread newThread = new Thread((o) => DoWork(o as object[]));
newThread.IsBackground = true;
newThread.Priority = ThreadPriority.AboveNormal;
newThread.Start(temp as object);
localThreads.Add(newThread);
}
//All threads initiated, now we pulse all
lock(signal){
Monitor.PulseAll(signal);
}
int counter = 0;
while(true){
if(counter == localThreads.Count){ break; }
localThreads[counter].Join();
counter++;
}
}
That's what done by the main thread (removed a few uneccessary pieces) and as stated before the main thread will always get stuck in the Join() on the last thread in the list.
This is how the method of the threads look like:
private void DoWork(object[] arguments){
lock(signal){
Monitor.Wait(signal);
}
GoDoWork(arguments);
}
Are there any other barriers I can use for this type of signaling? All I want is to let the main thread signal all threads at the same time so that they start at the same time. I want them to start at the same time inorder to have as close parallel as possible (I measure running time for the algorithm and a few other things). Is there any part of my barrier or code that is flawed (with the barrier I mean)? I tried running an instance with fewer threads and it still get stuck on the last one, I don't know why it is. I have confirmed by via VS debug that the last thread is sleeping (all other threads are !isAlive, while the last one isAlive = true).
Any help appreciated!
I managed to solve it using the Barrier class. Many thanks to Damien_The_Unbeliever! Still can't believe I haven't heard of it before.
public Barrier barrier = new barrier(1);
public void RunAlgorithm(List<City> cities){
List<Thread> localThreads = new List<Thread>();
object[] temp = //some parameters here
for(int i = 0; i < numOfCitiesToCheck; i++){
barrier.AddParticipant();
Thread newThread = new Thread((o) => DoWork(o as object[]));
newThread.IsBackground = true;
newThread.Priority = ThreadPriority.AboveNormal;
newThread.Start(temp as object);
localThreads.Add(newThread);
}
barrier.SignalAndWait();
int counter = 0;
while(true){
if(counter == localThreads.Count){ break; }
localThreads[counter].Join();
counter++;
}
}
private void DoWork(object[] arguments){
barrier.SignalAndWait();
GoDoWork(arguments);
}

Replacing a While loop with AutoResetEvent for blocking a thread

Recently, I was finally able to make a separate thread work. Now I am trying to master synchronization.
As far as I know, pausing a thread with ThreadName.Suspend() is not a good idea. At fist I used a While loop to block the thread. Later I noticed that this consumes resources, so now I am trying to replace the loop with an AutoResetEvent.
Here is some code (tell me if you the full code):
private void combTester(object sender, EventArgs e)//happens in a timer, because it manipulates the GUI
{
if (!timer2Block)
{
//stuff happens
genBlock = false;//unblocks the thread
timer2Block = true;//blocks itself
//debugging stuff happens
}
if (done)
timer2.Enabled = false;
}
private void combGenerator(int currEl, int begVal)
{
//setting a variable
for (int c = begVal; c <= currEl + totalCells - maxCells; c++)
{
while (genBlock && !abortTime)
{
if (abortTime)
return;
}
genBlock = true;//blocks itself
//some recursive stuff happens,
//because of which I was forced to use a thread instead of timers
}
}
I tried different places to put the Wait() and Set() methods, but both the tread and the timer get blocked and I don't know how to debug the program.
So, how can I replace the While loop with AutoResetEvent?
If what you want is to have a "pause" control for the worker thread then you should use a ManualResetEvent: keep the event signaled, and reset it when you want the thread to pause:
private void combGenerator(int currEl, int begVal)
{
for (int c = begVal; c <= currEl + totalCells - maxCells; c++)
{
manualResetEvent.WaitOne();
// do stuff
}
}
You can now pause/unpause the combGenerator thread by doing manualResetEvent.Reset() and manualResetEvent.Set() correspondingly.
This can be further expanded to include an "abort" signal by throwing in another ManualResetEvent (this could also be an AutoResetEvent, but as it's only going to do something once the distinction is not important):
var events = new[] { abortEvent, pauseEvent }; // order MATTERS!
for (int c = begVal; c <= currEl + totalCells - maxCells; c++)
{
var index = WaitHandle.WaitAny(events);
if (index == 0) {
// abort!
}
// do stuff
}
The magic here happens inside WaitAny. This method will wait for any of the events to become signaled and return the smallest index among the events that were signaled, if more than one. This is extremely important, as it will allow us to determine if we should abort.
During normal operation abortEvent will not be signaled and pauseEvent will be, so WaitAny will immediately return 1. If pauseEvent is reset then WaitAny will block until one of the events is again signaled. And if abortEvent is signaled then WaitAny will return 0, which is the cue to exit.
You can use another flag that checks whether it is recursive call or not, based on which you can decide to continue, or wait.
Example:
static int recCount = 0;
private void combGenerator(int currEl, int begVal)
{
//setting a variable
for (int c = begVal; c <= currEl + totalCells - maxCells; c++)
{
while (genBlock && !abortTime and recCount < 1)
{
if (abortTime)
return;
}
genBlock = true;//blocks itself
recCount ++;
//some recursive stuff happens,
//because of which I was forced to use a thread instead of timers
//after all the stuff is done
recCount--;
}
}

Thread runs slow when Invoke UI-Element

i am programming a benchmark tool, that reads a bunch of variables from a local server in a thread.
int countReads = 1000;
Int64 count = 0;
for (int i = 0; i < countReads; i++)
{
Thread.CurrentThread.Priority = ThreadPriority.Highest;
DateTime start = DateTime.Now;
session.Read(null, 0, TimestampsToReturn.Neither, idCollection, out ReadResults, out diagnosticInfos);
DateTime stop = DateTime.Now;
Thread.CurrentThread.Priority = ThreadPriority.Normal;
TimeSpan delay = (stop - start);
double s = delay.TotalMilliseconds;
count += (Int64)s;
Dispatcher.Invoke(DispatcherPriority.Render, new Action(() =>
{
progressBar1.Value = i;
}));
}
double avg = (double)count / countReads;
Dispatcher.Invoke(DispatcherPriority.Input, new Action(() =>
{
listBox1.Items.Add(avg);
}));
I am calculating the timespan it took to proceed the read and getting the average timespan at the end.
DateTime start = DateTime.Now;
session.Read(null, 0, TimestampsToReturn.Neither, idCollection, out ReadResults, out diagnosticInfos);
DateTime stop = DateTime.Now
if i run the code without updating the progressbar it took about 5ms average.
but if i run it with
Dispatcher.Invoke(DispatcherPriority.Render, new Action(() =>
{
progressBar1.Value = i;
}));
it takes about 10 ms average.
My question is, why is the timespan higher when using the progressbar?
i am just calculating the timespan for the read. Not including the progressbar update.
Is there any way to evacuate the ui-painting so that it doesn´t effect my read-timespan?
Thanks for your help.
Best regards
Stop using Invoke to transfer progress information to the UI thread. Publish the progress information to a shared data structure or variable and have the UI thread poll for it using a timer on a reasonable interval. I know it seems like we have all been brainwashed into thinking Invoke is the be-all method for doing worker-to-UI thread interactions, but for simple progress information it can be (and often is) the worst method.
A polling method using a timer on the UI thread offers the following benefits.
It breaks the tight coupling that Invoke imposes on both the UI and worker threads.
The UI thread gets to dictate when and how often it should update the progress information instead of the other way around. When you stop and think about it this is how it should be anyway.
You get more throughput on both the UI and worker threads.
I know this does not directly answer your question as to why session.Read appears to run slower. Try changing your strategy for updating progress information from a push model (via Invoke) to a pull model (via a timer). See if that makes a difference. Even if it does not I would still stick with the pull model for the reasons listed above.
Here is what MSDN says about Dispatcher.Invoke
Executes the specified delegate synchronously on the thread the Dispatcher is associated with.
So, basically, Dispatcher.Invoke blocks until the dispatcher thread as handled the request.
Try Dispatcher.BeginInvoke instead.
If current executing thread is associated with Dispatcher you are using - Invoke() will block this thread so in this case try out using Dispatcher.BeginInvoke() it will do the job asynchronously.
MSDN, Dispatcher.Invoke Method:
Invoke is a synchronous operation; therefore, control will not return
to the calling object until after the callback returns.
BTW, just of interest try out DispatcherPriority.Send
I came 9 years late to the party, but I think this is an even easier solution: Just wait until the progress bar value reaches a certain threshold before updating it. In my example, I refresh the toolbar every fifth of the maximum value.
private static int progressBarMaxValue = -1;
private static int progressBarChunkSize = -1;
public static void progressBarSetNotRealTimeValue(ProgressBar progressBar, int argNewValue)
{
if (progressBarMaxValue != -1)
{
if (argNewValue < progressBarChunkSize)
{
//Threshold not reached yet, discard the new value.
return;
}
else
{
//Allow the update, and set the next threshold higher.
progressBarChunkSize += progressBarChunkSize;
}
}
if (Thread.CurrentThread.IsBackground)
{
progressBar.BeginInvoke(new Action(() =>
{
if (progressBarMaxValue == -1)
{
progressBarMaxValue = progressBar.Maximum;
progressBarChunkSize = progressBar.Maximum / 5;
}
progressBar.Value = argNewValue;
}));
}
else
{
progressBar.Value = argNewValue;
}
}

Race condition during thread start?

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 ;)

Categories

Resources