Имеются ли проверки на отсутствие потоков?
У меня есть код, в котором исключения набросаются на новый поток, который мне нужно подтвердить и обсудить в главной теме. Для этого я разделяю состояние между потоками, используя поле, которое содержит исключение.
Мой вопрос Нужно ли использовать блокировки при проверке нулевого, как я делаю в следующем примере кода?
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?
}
}
}
}
Кроме того, нужно ли использовать блокировку при выбросе исключения в главный поток?
Ответы
Ответ 1
Первое, что нужно отметить, это то, что ваш код не является потокобезопасным, потому что у вас есть гонка потоков: вы проверяете CheckIsExceptionNull
в другой заблокированной области, куда вы бросаете, но: значение может меняться между тестом и броском.
Доступ к полям не гарантируется потоком. В частности, в то время как ссылки не могут разорваться (что гарантировано - чтение и запись ссылок являются атомарными), не гарантируется, что в разных потоках будут отображаться последние значения из-за кэширования ЦП и т.д. очень маловероятно, чтобы на самом деле вас укусить, но проблема с проблемами потоковой передачи в общем случае p
Лично я, вероятно, просто сделаю поле неустойчивым и использую локальный. Например:
var tmp = _exception;
if(tmp != null) throw tmp;
Вышеупомянутая не имеет ничьей гонки. Добавление:
volatile Exception _exception;
гарантирует, что значение не кэшируется в регистре (хотя это технически является побочным эффектом, а не предполагаемым/документированным эффектом volatile
)
Ответ 2
Там может быть много интересной и полезной информации о таких вопросах. Вы можете потратить часы на чтение сообщений в блогах и книг об этом. Даже люди, которые действительно знают это, не согласны. (Как вы можете видеть в сообщении от Марка Гравелла и Эрика Липперта).
Итак, у меня нет ответа на этот вопрос. Просто предложение: Всегда использовать блокировки. Как только более один поток обращается к полю. Никакого риска, никаких угадываний, обсуждений о технологии компилятора и процессора. Просто используйте блокировки и сохраняйте их, чтобы они работали не только в большинстве случаев на вашем компьютере, но и в каждом случае на каждой машине.
Дальнейшее чтение: