C# 一个读者,许多作家

C# 一个读者,许多作家,c#,.net,multithreading,exception,queueuserworkitem,C#,.net,Multithreading,Exception,Queueuserworkitem,相关的: 我正在捕获由启动的后台线程中的异常,并通过共享实例变量将它们传播到主线程 后台线程执行以下操作: try { ... stuff happens here... } catch (Exception ex1) { lock(eLock) { // record only the first exception if (_pendingException == null) _pendingExceptio

相关的:

我正在捕获由启动的后台线程中的异常,并通过共享实例变量将它们传播到主线程

后台线程执行以下操作:

try
{
    ... stuff happens here...
}
catch (Exception ex1)
{
    lock(eLock) 
    {
        // record only the first exception
        if (_pendingException == null) 
            _pendingException = ex1;
    }
}
有多个潜在的写入程序要处理_pendingException-多个后台线程-所以我用锁来保护它

在主线程中,我必须在读取
\u pendingException
之前获取锁吗?或者我可以简单地这样做:

if (_pendingException != null)
    ThrowOrHandle(); 

编辑:

ps:我不想在读卡器线程上设置锁,因为它在热路径上,我会经常设置并释放锁

你不可能这么容易逃脱。如果另一个线程在读取器处理现有线程之前抛出异常,则会丢失异常。这里需要的是一个同步队列:

try { ... stuff happens here... } catch (Exception ex1) { lock(queue) { queue.Enqueue(ex1); Monitor.PulseAll(queue); } } 尝试 { …这里发生的事情。。。 } 捕获(异常ex1) { 锁(队列) { queue.Enqueue(ex1); Monitor.pulsell(队列); } } 并要处理它:

while(!stopped) lock (queue) { while (queue.Count > 0) processException(queue.Dequeue()); Monitor.Wait(queue); } 当(!停止) 锁(队列) { 而(queue.Count>0) processException(queue.Dequeue()); 监视器。等待(队列); }
你不可能这么容易脱身。如果另一个线程在读取器处理现有线程之前抛出异常,则会丢失异常。这里需要的是一个同步队列:

try { ... stuff happens here... } catch (Exception ex1) { lock(queue) { queue.Enqueue(ex1); Monitor.PulseAll(queue); } } 尝试 { …这里发生的事情。。。 } 捕获(异常ex1) { 锁(队列) { queue.Enqueue(ex1); Monitor.pulsell(队列); } } 并要处理它:

while(!stopped) lock (queue) { while (queue.Count > 0) processException(queue.Dequeue()); Monitor.Wait(queue); } 当(!停止) 锁(队列) { 而(queue.Count>0) processException(queue.Dequeue()); 监视器。等待(队列); }
尽管您可能只关心第一个异常,但出于至少两个原因,您可能仍然希望使用lock:

  • 在多核CPU中,在不使变量易失性(或执行任何内存屏障操作)的情况下,可能会出现在不同核上运行的线程看到不同值的时刻。(我不确定在工作线程中调用
    lock(queue)
    是否会导致任何内存障碍操作)。(更新)在工作线程中调用
    lock(queue)
    将导致内存障碍操作,Eric在下面的评论中指出了这一点
    二,。请记住(Eric Lippert)(如果您假设引用是32位CLR中可以原子读取的32位地址)。引用的实现可以更改为一些不透明的结构,这些结构可能不会在将来的CLR版本中自动读取(尽管我认为在可预见的将来不太可能发生:),您的代码将崩溃

    尽管您可能只关心第一个异常,但出于至少两个原因,您可能仍然希望使用lock:

  • 在多核CPU中,在不使变量易失性(或执行任何内存屏障操作)的情况下,可能会出现在不同核上运行的线程看到不同值的时刻。(我不确定在工作线程中调用
    lock(queue)
    是否会导致任何内存障碍操作)。(更新)在工作线程中调用
    lock(queue)
    将导致内存障碍操作,Eric在下面的评论中指出了这一点
    二,。请记住(Eric Lippert)(如果您假设引用是32位CLR中可以原子读取的32位地址)。引用的实现可以更改为一些不透明的结构,这些结构可能不会在将来的CLR版本中自动读取(尽管我认为在可预见的将来不太可能发生:),您的代码将崩溃

    对引用的读取和写入是原子的(请参阅),我几乎可以肯定锁确实会创建内存屏障,所以您所做的可能是安全的


    但实际上,只要在阅读时使用锁就可以了。它保证工作;如果您每次都看到它不是在锁中被访问的,您就知道出了问题,如果锁导致了您的性能问题,那么您太频繁地检查标志,这只是“正确的做法”。

    对引用的读取和写入是原子的(请参阅)我几乎可以肯定,锁确实会造成记忆障碍,所以你们所做的可能是安全的


    但实际上,只要在阅读时使用锁就可以了。它保证工作;如果您每次都看到它不是在锁中被访问的,您就知道有什么地方出了问题,如果锁导致了性能问题,那么您就太频繁地检查标志,而这正是“正确的做法”。

    我真的只想要第一个例外-这是一种快速失败的方法。没有恢复。所以我不在乎我是否错过了例外2..n。我只想要第一个。我真的只想要第一个例外——这是一种快速失败的方法。没有恢复。所以我不在乎我是否错过了例外2..n。我只想要第一个。你是不是?除了传回的例外,你在做什么?或者您可以使用bool来标记发生了错误吗?zdnet?不,我甚至不知道那是什么。嗯,承租人。。。我正在使用异常。。。嗯,是的。我从主线程中重新引用了它。你的zdnet不是吗?除了传递回来的异常,你在做什么吗?或者您可以使用bool来标记发生了错误吗?zdnet?不,我甚至不知道那是什么。嗯,承租人。。。我正在使用异常。。。嗯,是的。我从主线程中重新引用它。问题是,主线程是读取_pendingException字段的线程。我不想在读卡器线程上使用锁,因为它在热路径上,我会经常使用并释放锁。为什么不想在主线程上使用锁?您是否尝试过,发现它太慢了,或者这是过早的优化?如果它导致您出现问题,那么您的轮询该标志的方式过于频繁,应该选择不同的通知策略,例如,在出现错误时调用委托,而不是轮询标志。问题是,主线程是在