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() 中,我正在捕获异常并在那里记录。

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

4

3 回答 3

1

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

由于您使用的是 Winforms,因此通知主线程的最简单方法是使用Invoke. 有关示例,请参见以下问题。

于 2013-06-23T08:36:15.970 回答
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);
}

我希望这有帮助。

于 2013-06-23T08:00:07.537 回答
0

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

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);
            }
        }
    }
}
于 2013-06-27T06:09:20.547 回答