Должен ли доступ к общему ресурсу быть заблокирован родительским потоком перед созданием дочернего потока, который обращается к нему? - PullRequest
3 голосов
/ 10 февраля 2010

Если у меня есть следующий псевдокод:

sharedVariable = somevalue;
CreateThread(threadWhichUsesSharedVariable);

Теоретически возможно, чтобы многоядерный процессор выполнял код в threadWhichUsesSharedVariable (), который считывает значение sharedVariable до того, как родительский поток записывает в него? Для полного теоретического предотвращения даже отдаленной возможности состояния гонки, если код будет выглядеть следующим образом:

sharedVariableMutex.lock();
sharedVariable = somevalue;
sharedVariableMutex.unlock();
CreateThread(threadWhichUsesSharedVariable);

По сути, я хочу знать, явно ли порождает поток линеаризацию ЦП в этой точке и гарантированно это делает.

Я знаю, что накладные расходы на создание потоков, вероятно, занимают достаточно времени, чтобы это никогда не имело значения на практике, но перфекционист во мне боится теоретического состояния гонки. В экстремальных условиях, когда некоторые потоки или ядра могут сильно отставать, а другие работают быстро и эффективно, я могу представить себе, что удаленный порядок выполнения (или доступа к памяти) может быть удален, если не было блокировки.

Ответы [ 2 ]

2 голосов
/ 11 февраля 2010

Я бы сказал, что ваш псевдокод безопасен для любого корректно функционирующего многопроцессорная система. Компилятор C ++ не может сгенерировать вызов CreateThread() до sharedVariable получил правильное значение если он не сможет доказать себе, что это безопасно. Вам гарантировано что ваш однопоточный код выполняется эквивалентно неупорядоченный линейный путь выполнения. Любая система, которая "искажает время" Создание потока перед назначением переменной серьезно нарушено.

Я не думаю, что объявление sharedVariable как изменчивое делает что-либо полезно в этом случае.

1 голос
/ 11 февраля 2010

Учитывая ваш пример , и если вы используете Java, то ответ будет "Нет". В Java поток не может появиться и прочитать ваше значение до завершения операции присваивания. В некоторых других языках это может быть другая история.

"Переменные, совместно используемые несколькими потоками (например, переменные экземпляра объектов), имеют атомарное назначение, гарантированное спецификацией языка Java для всех типов данных, кроме длинных и двойных ... Если метод состоит только из единственной переменной доступа или присваивание, нет необходимости делать его синхронизированным для обеспечения безопасности потоков, и нет никаких причин не делать это для производительности. " ссылка

Если ваш double или long объявлен volatile, то вам также гарантируется, что присвоение является атомарной операцией.

Обновление: Ваш пример будет работать в C ++ так же, как он работает в Java. Теоретически не существует способа, чтобы порождение потока началось или завершилось до назначения, даже с выполнением вне порядка.

Обратите внимание, что ваш пример ОЧЕНЬ специфичен, и в любом другом случае рекомендуется убедиться, что общий ресурс защищен должным образом. Новый стандарт C ++ предлагает много атомарного материала, так что вы можете объявить вашу переменную как атомарную, и операция присваивания будет видна всем потокам без необходимости блокировки. CAS (сравните и установите) - ваш следующий лучший вариант.

...