Reputation: 46
public class ProducerConsumerQueue
{
public void EnqueueTask(MyTask task)
{
}
void Work()
{
while (true)
{
try
{
// my task goes here
Thread.Sleep(2000);
}
catch(Exception ex)
{
Log(ex);
}
}
}
}
Producer:
public void Add()
{
MyTask task = new MyTask();
new ProducerConsumerQueue().EnqueueTask(task);
}
I'm in .NET 3.5.
Add() method will be called by my API users. In the example above, inside the method, void work(), I'm catching the exception and logging there.
But instead of that, I would like to catch and rethrow the exception to the user. Sametime, the permanent thread that run inside the while loop, should recover from the exception by continue to the next task in the queue. My short question is - How will I throw exception that happen inside void work(), but still the consumer stay alive for next task in the queue.
Upvotes: 0
Views: 1151
Reputation: 101150
Introduce a callback which is invoked when the task has completed:
public interface ICompletionState
{
public ITask Task { get; set; }
public Exception Exception { get; set; }
}
public class CompletionState : ICompletionState
{
public ITask Task { get; set; }
public Exception Exception { get; set; }
public Action<ICompletionState> Callback { get; set; }
}
public class ProducerConsumerQueue
{
ConcurrentQueue<CompletionState> _tasks = new ConcurrentQueue<CompletionState>();
public void EnqueueTask(ITask task, Action<ICompletionState> callback)
{
_tasks.Enqueue(new CompletionState{ Task = task, Callback = callback });
}
void Work()
{
while (true)
{
CompletionState cs;
try
{
if (!_tasks.TryDequeue(out cs))
continue;
cs.Task.Execute();
cs.Callback(cs);
}
catch(Exception ex)
{
cs.Exception = ex;
cs.Callback(cs);
}
}
}
}
Upvotes: 0
Reputation: 39023
You need to establish some sort of communications between your consumer threads and the main thread. When a consumer encounters an exception, it should notify the main thread and move on to the next task.
Since you're using Winforms, the easiest way to inform the main thread is to use Invoke
. See the following question for an example.
Upvotes: 1
Reputation: 15158
Continuing our discussion from the comments, you could possibly do something like collecting all the exceptions occurring when executing a queue of tasks (however you need to execute the queue on cycles) and then throwing it back to the caller. So something like:
public void ExecuteAllTasks()
{
var exceptions = new List<Exception>();
IEnumerable<MyTask> tasks = GetQueuedTasks(); // get all tasks (or possibly pass them to the method) ...
foreach (MyTask task in tasks)
{
try
{
// execute your tasks here ...
}
catch (Exception ex)
{
// collect all the exceptions
exceptions.Add(ex);
}
}
// throw all the errors at once
if (exceptions.Any())
throw new AggregateException(_exceptions);
}
I hope this helps.
Upvotes: 1