Ответ 1
Мне все равно, когда точно m_Done будет установлено значение true. Мой вопрос заключается в том, что у меня есть гарантия от спецификации языка С# и параллельной библиотеки задач, которая в конечном итоге m_Done будет истинна, если я получаю доступ к ней из другого потока?
Нет.
Чтение m_Done
является энергонезависимым и поэтому может перемещаться произвольно далеко назад во времени, и результат может быть кэширован. В результате можно было бы наблюдать false
за каждый прочитанный за все время.
Мне нужно знать, будет ли текущий код работать так же, если он работает на x86, x64, Itanium или ARM.
В спецификации отсутствует гарантия того, что код будет соблюден, чтобы делать то же самое на сильных (x86) и слабых (ARM) моделях памяти.
В спецификации достаточно ясно, какие гарантии сделаны для энергонезависимых чтений и записей: они могут быть произвольно перенаправлены на разные потоки при отсутствии определенных специальных событий, таких как блокировки.
Прочитайте спецификацию для деталей, особенно бит о побочных эффектах, поскольку они связаны с изменчивым доступом. Если после этого у вас появилось больше вопросов, задайте новый вопрос. Это очень сложный материал.
Кроме того, вопрос предполагает, что вы игнорируете существующие механизмы, которые определяют, что задача завершена, и вместо этого сворачивайте свои собственные. Существующие механизмы были разработаны экспертами; используйте их.
Я вижу много кода, написанного таким образом (без блокировок или volatile), и я не уверен, что это правильно.
Это почти наверняка не.
Хорошее упражнение для человека, написавшего этот код, таково:
static volatile bool q = false;
static volatile bool r = false;
static volatile bool s = false;
static volatile bool t = false;
static object locker = new object();
static bool GetR() { return r; } // No lock!
static void SetR() { lock(locker) { r = true; } }
static void MethodOne()
{
q = true;
if (!GetR())
s = true;
}
static void MethodTwo()
{
SetR();
if (!q)
t = true;
}
После инициализации полей MethodOne вызывается из одного потока, MethodTwo вызывается из другого. Обратите внимание, что все нестабильно и что запись в r не только изменчива, но и полностью огорожена. Оба метода закончены нормально. Возможно ли впоследствии, когда s и t будут наблюдаться как истинное в первой нити? Возможно ли это на x86? Это не так; если первый поток выигрывает гонку, то t остается ложным, а если второй поток побеждает, то s остается ложным; этот анализ неверен. Зачем? (Подсказка: как разрешено x86 переписывать MethodOne
?)
Если кодер не может ответить на этот вопрос, они почти наверняка не смогут корректно программировать с изменчивым и не должны делиться памятью через потоки без блокировок.