Hol*_*olf 11 c# null exception thread-safety
我有一些代码,在新线程上抛出异常,我需要在主线程上确认和处理.为了实现这一点,我通过使用保存抛出异常的字段来共享线程之间的状态.
我的问题是在检查null时是否需要使用锁,因为我在以下代码示例中进行操作?
public class MyClass
{
readonly object _exceptionLock = new object();
Exception _exception;
public MyClass()
{
Task.Run(() =>
{
while (CheckIsExceptionNull())
{
// This conditional will return true if 'something has gone wrong'.
if(CheckIfMyCodeHasGoneWrong())
{
lock(_exceptionLock)
{
_exception = new GoneWrongException();
}
}
}
});
}
bool CheckIsExceptionNull() // Is this method actually necessary?
{
lock (_exceptionLock)
{
return _exception == null;
}
}
// This method gets fired periodically on the Main Thread.
void RethrowExceptionsOnMainThread()
{
if (!CheckIsExceptionNull())
{
lock (_exceptionLock)
{
throw _exception; // Does this throw need to be in a lock?
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
另外,在主线程上抛出异常时是否需要使用锁?
首先要注意的是,你的代码不是线程安全的,因为你有一个线程竞争:你CheckIsExceptionNull在一个不同的锁定区域中检查你抛出的位置,但是:值可以在测试和throw之间改变.
不保证字段访问是线程安全的.特别是,虽然引用不能 被破坏(保证很多 - 引用的读取和写入是原子的),但由于CPU缓存等原因,不能保证不同的线程会看到最新的值.实际上不太可能咬你,但这是一般情况下线程问题的问题; p
就个人而言,我可能只是让这个领域变得不稳定,并使用本地.例如:
var tmp = _exception;
if(tmp != null) throw tmp;
Run Code Online (Sandbox Code Playgroud)
以上没有线程竞赛.添加:
volatile Exception _exception;
Run Code Online (Sandbox Code Playgroud)
确保该值不会缓存在寄存器中(尽管这在技术上是副作用,而不是预期/记录的效果volatile)