I've a main thread called t1:
Thread t1 => new Thread(UpdateResults);
that execute a method called UpdateResult this method require internet connection. Now sometimes the connection could be broken.
When the connection is down, the method UpdateResult return an exception and the thread t1 terminate the execution.
I need to execute again the thread t1 so I though to create another thread t2 that check recursively if the thread t1 is running or no.
Both thread are started automatically. This is the code of thread t2 method:
while (true)
{
if (!t1.IsAlive)
{
t1.Start();
}
}
this code unfortuntely slow down the app UI, 'cause is an infinite loop.
What I can do instead for fix this?
Instead of wasting another thread t2 just to watch t1, you may consider to change the method of thread t1:
Thread t1 = new Thread(o =>
{
while (true)
{
try
{
UpdateResult();
}
catch (Exception)
{
// do some error handling
}
Thread.Sleep(100);
}
});
So you catch the exception (without rethrowing it!) and prevent the crash of the whole thread.
This is of course only a simple example. You should try to catch only the specific exception for a broken connection and add proper error handling (e.g. logging etc.).
And adjust the time the thread should sleep according to your needs.
One approach to avoid an infinite polling is to Join the thread, and re-spawn it when it stops:
while (true) {
t1.Join();
t1 = ... // Make a replacement thread
t1.Start();
}
It goes without saying that this should not be done from UI thread, because Join() blocks indefinitely.
If you want to stick with your architecture, something as simple as waiting a second in each loop of Thread t2 would massively improve performance.
while (true)
{
if(!t1.isAlive)
{
t1.Start();
}
Thread.Sleep(1000);
}
(You can adjust the time to anything that makes sense in your context.)
Though instead of this multi-thread solution, i would ask: why does thread t1 terminate because of an Exception? You can catch it with a try-catch block.
Instead of UpdateResults call SafeUpdateResults which just says:
void SafeUpdateResults()
{
while (true)
{
try { UpdateResults(); }
catch (Exception e)
{
//track the Error if you want
Console.WriteLine("t1-Error: " + e.Message);
}
}
}
I would even recommend, going into the function UpdateResults() and catching the Exception right where it happens, and then reacting accordingly (though this here is arguably easier).
Related
This question already has answers here:
How do I abort/cancel TPL Tasks?
(13 answers)
Closed 2 years ago.
The community reviewed whether to reopen this question 8 months ago and left it closed:
Original close reason(s) were not resolved
When using Parallel.ForEach(), is there a way to forcefully execute Thread.Abort on a specific thread?
I know that Thread.Abort() is not recommended.
I'm running a Parallel.ForEach() on a collection of a hundreds of thousands of entities.
The loop processes data going back 30 years in some cases. We've had a few issues where a thread hangs. While we are trying to get a grasp on that, was hoping to call implement a fail safe. If the thread runs for more than x amount of time, forcefully kill the thread.
I do not want to use a cancellation token.
It would be ugly, but haven't come to another solution. Would it be possible to:
Have each thread open a timer. Pass in reference of Thread.CurrentThread to timer
If the timer elapses, and processing hasn’t completed, call Thread.Abort on that timer
If needed, signal event wait handle to allow next patient to process
private void ProcessEntity(ProcessParams param,
ConcurrentDictionary<long, string> entities)
{
var options = new ParallelOptions
{
MaxDegreeOfParallelism = 2
};
Parallel.ForEach(person, options, p =>
{
ProcessPerson(param, p);
});
}
internal void ProcessPerson(ProcessParams param, KeyValuePair<long, string> p)
{
try
{
//...
}
catch (Exception ex)
{
}
param.eventWaitHandle?.WaitOne();
}
It seems that the Parallel.ForEach method is not resilient in the face of its worker threads being aborted, and behaves inconsistently. Other times propagates an AggregateException that contains the ThreadAbortException, and other times it throws an ThreadAbortException directly, with an ugly stack trace revealing its internals.
Below is a custom ForEachTimeoutAbort method that offers the basic functionality of the Parallel.ForEach, without advanced features like cancellation, loop state, custom partitioners etc. Its special feature is the TimeSpan timeout parameter, that aborts the worker thread of any item that takes too long to complete.
public static void ForEachTimeoutAbort<TSource>(
this IEnumerable<TSource> source,
Action<TSource> action,
int maxDegreeOfParallelism,
TimeSpan timeout)
{
// Arguments validation omitted
var semaphore = new SemaphoreSlim(maxDegreeOfParallelism, maxDegreeOfParallelism);
var exceptions = new ConcurrentQueue<Exception>();
try
{
foreach (var item in source)
{
semaphore.Wait();
if (!exceptions.IsEmpty) { semaphore.Release(); break; }
ThreadPool.QueueUserWorkItem(_ =>
{
var timer = new Timer(state => ((Thread)state).Abort(),
Thread.CurrentThread, Timeout.Infinite, Timeout.Infinite);
try
{
timer.Change(timeout, Timeout.InfiniteTimeSpan);
action(item);
}
catch (Exception ex) { exceptions.Enqueue(ex); }
finally
{
using (var waitHandle = new ManualResetEvent(false))
{
timer.Dispose(waitHandle);
// Wait the timer's callback (if it's queued) to complete.
waitHandle.WaitOne();
}
semaphore.Release();
}
});
}
}
catch (Exception ex) { exceptions.Enqueue(ex); }
// Wait for all pending operations to complete
for (int i = 0; i < maxDegreeOfParallelism; i++) semaphore.Wait();
if (!exceptions.IsEmpty) throw new AggregateException(exceptions);
}
A peculiarity of the ThreadAbortException is that it cannot be caught. So in order to prevent the premature completion of the parallel loop, the Thread.ResetAbort method must be called from the catch block.
Usage example:
ForEachTimeoutAbort(persons, p =>
{
try
{
ProcessPerson(param, p);
}
catch (ThreadAbortException)
{
Thread.ResetAbort();
}
}, maxDegreeOfParallelism: 2, timeout: TimeSpan.FromSeconds(30));
The .NET Framework is the only platform where the ForEachTimeoutAbort method could be used. For .NET Core and .NET 5 one could try converting it to ForEachTimeoutInterrupt, and replace the call to Abort with a call to Interrupt. Interrupting a thread is not as effective as aborting it, because it only has effect when the thread is in a waiting/sleeping mode. But it may be sufficient in some scenarios.
I'm implementing a Method called by someone else. If my Method takes to long the caller will call Thread.Abort(). I start some tasks in my Method, and need to cancel those if my thread get aborted.
I currently guess the timeout I have and cancel the tasks after this timespan. It is not always the same timeout, depending on the operations executed before my method.
Are there a way to tie my tasks to that thread lifetime?
Update
To prevent any further comments, that I should not use Thread.Abort(), this is the code that handles the abort (not called by me, can't change that):
using (var cancelationTokenSource = new CancellationTokenSource())
{
try
{
DoWork(cancelationTokenSource.Token);
}
catch (ThreadAbortException)
{
cancelationTokenSource.Cancel();
throw;
}
}
I use the CancellationToken not Thread.Abort()
You can handle ThreadAbortException to deal with cleanup, including aborting other threads if ncessary.
void MyThreadProc()
{
try
{
//Do interesting things
}
catch ( ThreadAbortException e )
{
childThread.Abort();
}
}
I have threads inside thread and the last sub-thread just hangs and doesn't throw anything for 20 hrs now. My code was something like this:
bool end = false;
var t1 = new Thread(() =>
{
// ...
var t2 = new Thread(() =>
{
try
{
foreach(Data data in datas2)
{
foreach(SubData subdata in data.SubDatas)
{
var t3 = new Thread(() =>
{
this.SaveData(subdata.RetrieveData());
}); t3.Start();
if (!t3.Join(1800000))
{
t3.Abort();
throw new TimeoutException("The execution of method is taking too long.");
}
}
}
} catch { throw; }
finally { end = true; }
}); t2.Start();
}); t1.Start();
It never goes through the finally block of t2 and it doesn't throw any error. What is happening here?
My code is in C#, framework 4, build in Visual Studio 2010 Pro.
Please help. Thanks in advance.
Edit:
Thanks everyone for your help. I have found the answer and it is
an infinite loop.
Our production stopped for a week for this stupid bug. Ugh. It seems like there has a validation on our system that creates an infinite loop for some data only. Thanks everyone for being enthusiastic in solving this question.
I don't know if this the problem in your case....
However, Thread.Abort raises an exception ( a special one, that even if you catch it, once the catch and finally have finished it will auto rethrow itself unless you clear the abort ). If the code in SaveData and RetriveData catch the exception and then either in the catch or finally end up being blocked, it won't abort.
There is probably something going on in SaveData or RetrieveData that we don't know about. It is possible that you could be doing extremely long/repetetive I/O that we don't know about.
Additionally, I don't think that this code is doing what you think it is doing. See my //NOTE: below:
foreach(SubData subdata in data1.SubDatas)
{
var t3 = new Thread(() =>
{
this.SaveData(subdata.RetrieveData());
}); t3.Start();
// NOTE: Here you are blocking each iteration of T2
// while T3 runs. There is no reason to be running
// another thread here- just call SaveData/RetrieveData
// from T2. Additionally, because this is executing in
// a double-nested loop, you might be doing this many,
// many times. I'd suggest looking into ThreadPool or TPL.
if (!t3.Join(1800000))
{
t3.Abort();
throw new TimeoutException("The execution of method is taking too long.");
}
}
I'm using an invocation described in this question: Synchronization accross threads / atomic checks?
I need to create an method invoker that any thread can call, which will execute on the main executing thread at a specific given point in its execution.
I ended up using this implementation of the Invoker class:
I am aware that is might not be the most efficient in terms of locking, but it's theoretically working in a similar enough way than Thread.MemoryBarrier(), such as the one SLaks suggested.
EDIT: With MRAB's suggestions.
public class Invoker
{
private Queue<Action> Actions { get; set; }
public Invoker()
{
this.Actions = new Queue<Action>();
}
public void Execute()
{
Console.WriteLine("Executing {0} actions on thread {1}", this.Actions.Count, Thread.CurrentThread.ManagedThreadId);
while (this.Actions.Count > 0)
{
Action action;
lock (this.Actions)
{
action = this.Actions.Dequeue();
}
action();
}
Console.WriteLine("Executed, {0} actions left", this.Actions.Count);
}
public void Invoke(Action action, bool block = true)
{
if (block)
{
Console.WriteLine("Invoking");
SemaphoreSlim semaphore = new SemaphoreSlim(0, 1);
lock (this.Actions)
{
this.Actions.Enqueue(delegate
{
try
{
action();
Console.WriteLine("Actioned");
}
catch
{
Console.WriteLine("Exception thrown by action");
throw;
}
finally
{
semaphore.Release();
Console.WriteLine("Released");
}
});
}
Console.WriteLine("Enqueued");
Console.WriteLine("Waiting on thread {0}", Thread.CurrentThread.ManagedThreadId);
semaphore.Wait();
Console.WriteLine("Waited");
semaphore.Dispose();
}
else
{
this.Actions.Enqueue(action);
}
}
}
The many Console.WriteLine are there to help me track my freezing, which happens regardless of whether or not this logging is present (i.e., they are not responsible of the freezing and can be discarded as culprits).
The freezing occurs in a scenario where:
An execution thread runs in a loop (calling Invoker.Execute).
On 2 other threads, 2 methods are invoked relatively simultaneously (calling Invoker.Invoke).
The first method works and gets invoked fine, but the second one freezes after "Waiting", that is, after semaphore.Wait().
Example output:
Executing 0 actions on thread 1
Executed, 0 actions left
Executing 0 actions on thread 1
Executed, 0 actions left
Invoking
Enqueued
Waiting on thread 7
Executing 1 actions on thread 1
Actioned
Released
Executed, 0 actions left
Waited
Invoking
Enqueued
Waiting on thread 8
What I suspect to be happening is that the execution thread somehow blocks, hence not executing the second enqueued action, and not releasing the semaphore (semaphore.Release()), and thus not allowing the execution to proceed.
But that is extremely weird (in my opinion), since the execution is on another thread than the semaphore blocking, and so it shouldn't block, right?
I've tried to build a test case that reproduces the problem out of the context environment, but I can't get it to reproduce. I post it here as an illustration of the 3 steps I explained earlier.
static class Earth
{
public const bool IsRound = true;
}
class Program
{
static Invoker Invoker = new Invoker();
static int i;
static void TestInvokingThread()
{
Invoker.Invoke(delegate { Thread.Sleep(300); }); // Simulate some work
}
static void TestExecutingThread()
{
while (Earth.IsRound)
{
Thread.Sleep(100); // Simulate some work
Invoker.Execute();
Thread.Sleep(100); // Simulate some work
}
}
static void Main(string[] args)
{
new Thread(TestExecutingThread).Start();
Random random = new Random();
Thread.Sleep(random.Next(3000)); // Enter at a random point
new Thread(TestInvokingThread).Start();
new Thread(TestInvokingThread).Start();
}
}
Output (as supposed to occur):
Executing 0 actions on thread 12
Executed, 0 actions left
Executing 0 actions on thread 12
Executed, 0 actions left
Invoking
Enqueued
Waiting on thread 13
Invoking
Enqueued
Waiting on thread 14
Executing 2 actions on thread 12
Actioned
Released
Waited
Actioned
Released
Waited
Executed, 0 actions left
Executing 0 actions on thread 12
Executed, 0 actions left
Executing 0 actions on thread 12
The actual question: What I'm asking, at this point, is if any experienced threading programmer can see a logical mistake in the Invoker class that could ever make it block, as I see no possible way of that happening. Similarly, if you can illustrate a test case that makes it block, I can probably find where mine went wrong. I don't know how to isolate the problem.
Note: I'm quite sure this is not really regarded as a quality question for its specificity, but I'm mostly posting as a desperate cry for help, as this is hobby programming and I have no coworker to ask. After a day of trial and error, I still can't fix it.
Important update: I just had this bug occur on the first invocation too, not necessarily only on the second. Therefore, it can really freeze by itself in the invoker. But how? Where?
I think you should lock on Actions when enqueuing and dequeuing. I occasionally had a null-reference exception here:
this.Actions.Dequeue()();
probably because a race condition.
I also think that the enqueued code should not dispose of the semphore, but just leave that to the enqueuing thread:
Console.WriteLine("Invoking");
SemaphoreSlim semaphore = new SemaphoreSlim(0, 1);
this.Actions.Enqueue(delegate
{
action();
Console.WriteLine("Actioned");
semaphore.Release();
Console.WriteLine("Released");
});
Console.WriteLine("Enqueued");
Console.WriteLine("Waiting");
semaphore.Wait();
Console.WriteLine("Waited");
semaphore.Dispose();
again because of race conditions.
EDIT: It has occurred to me that if the action throws an exception for some reason, the semaphore won't be released, so:
this.Actions.Enqueue(delegate
{
try
{
action();
Console.WriteLine("Actioned");
}
catch
{
Console.WriteLine("Exception thrown by action");
throw;
}
finally
{
semaphore.Release();
Console.WriteLine("Released");
}
});
Could that be the problem?
EDIT: Are you locking this.Actions when modifying it?
When dequeuing:
Action action;
lock (this.Actions)
{
action = this.Actions.Dequeue();
}
action();
and enqueuing:
lock (this.Actions)
{
this.Actions.Enqueue(delegate
{
...
});
}
Got it. It was a really deep multi-layer deadlock across my program, hence why I couldn't reproduce it easily. I will mark MRAB's answer as accepted however, for it might have been a real cause of locks caused by the Invoker itself.
How could you find out that an Exception occurred in a Thread in a MultiThreaded Application ? and consecutively clean the resources ?
Because otherwise the Thread can be still remaining in memory and running.
As Sean has said, you have to do all exception handling and cleanup inside the thread method, you can't do it in the Thread initialization. For example:
public void Run()
{
try
{
Thread thread1 = new Thread(ThreadEntry1);
thread1.Start();
Thread thread2 = new Thread(ThreadEntry2);
thread2.Start();
}
catch (NotImplementedException)
{
// Neither are caught here
Console.WriteLine("Caught you");
}
}
private void ThreadEntry1()
{
throw new NotImplementedException("Oops");
}
private void ThreadEntry2()
{
throw new NotImplementedException("Oops2");
}
Instead, this approach is more self-contained and obviously also works:
public void Run()
{
Thread thread1 = new Thread(ThreadEntry1);
thread1.Start();
}
private void ThreadEntry1()
{
try
{
throw new NotImplementedException("Oops");
}
catch (NotImplementedException)
{
Console.WriteLine("Ha! Caught you");
}
}
If you want to know if the Thread has failed, then you should consider an array of WaitHandles, and signal back to your calling method. An alternative and simpler approach is to simply increment a counter each time a thread's operation finishes:
Interlocked.Increment(ref _mycounter);
If you're worried about this sort of thing then you should wrap your threads entry point in a try/catch block and do the cleanup explicitly. Any exception passing out of the thread entry point will cause your app to shut down.
A. You have a call stack, and you can catch it inside the thread and add the thread id to the log I guess...
If you wrap your thread in a good manner, you can add cleaing code to the catch section, terminating the thread if needed.
You can catch exceptions within threads like you would any normal function.
If your "work" function for a thread is called DoWork then do something like this:
private void DoWork(...args...)
{
try
{
// Do my thread work here
}
catch (Exception ex)
{
}
}
Eric Lippert has a recent post on the badness of exceptions occurring in worker threads. It's worth reading and understanding that an exception is "exceptional" and the only thing that you can be sure of after an exception in a worker thread is that you can no longer be sure of the state of your application.