首页 文章

处理消费者队列中的异常

提问于
浏览
0
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);
            }
        }
    }
}

制片人:

public void Add()
{
    MyTask task = new MyTask();
    new ProducerConsumerQueue().EnqueueTask(task);
}

我在.NET 3.5中 .

我的API用户将调用Add()方法 . 在上面的例子中,在方法内部,void work(),我正在捕获异常并在那里记录 .

但不是那样,我想 grab 并重新抛出用户的异常 . Sametime,在while循环内运行的永久线程,应该继续执行队列中的下一个任务,从异常中恢复 . 我的简短问题是 - 如何抛出void work()中发生的异常,但仍然消费者为队列中的下一个任务保持活跃状态 .

3 回答

  • 1

    从评论继续我们的讨论,你可能会做一些事情,比如收集执行任务队列时发生的所有异常(但是你需要在循环上执行队列),然后将它扔回调用者 . 所以类似于:

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

    我希望这有帮助 .

  • 0

    您需要在消费者线程和主线程之间 Build 某种通信 . 当消费者遇到异常时,它应该通知主线程并继续下一个任务 .

    由于您使用的是Winforms,因此通知主线程的最简单方法是使用 Invoke . 有关示例,请参阅following question .

  • 1

    引入在任务完成时调用的回调:

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

相关问题