3

Если у меня есть следующие psuedocode:Должен ли доступ к общему ресурсу блокироваться родительским потоком до появления дочернего потока, который обращается к нему?

sharedVariable = somevalue;
CreateThread(threadWhichUsesSharedVariable);

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

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

В основном я хочу знать, если нерест поток явно линеаризует CPU в этой точке и гарантированно это сделает.

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

+0

Мой вопрос касается таких языков, как C++, где вы близки к уровню машины, и где «блокировка» достигается с помощью простого цикла InterlockedExchange. Я обеспокоен тем, что объявления переменных «volatile» недостаточно для обеспечения синхронизации. Разве нет разницы между «атомарным» и «синхронизированным»? Атомные операции не могут быть разделены - и если переменная объявлена ​​volatile, компилятор не будет переупорядочивать обращения к ней - но не может ли их переупорядочить? Особенно при доступе к различным ядрам? – Deadcode

+0

Дополнительные пояснения: В моем примере «sharedVariable = somevalue» используется для передачи данных в threadWhichUsesSharedVariable. Очень важно, чтобы threadWhichUsesSharedVariable только обращался к «sharedVariable» после того, как он был назначен родительским потоком. – Deadcode

+1

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

ответ

2

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

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

1

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

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

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

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

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

+0

Спасибо за ваш ответ, но я действительно спрашивал о C++ (или любом языке, который приближает вас к уровню машины) и должен был сказать это. Я добавлю комментарий, разъясняющий мой вопрос. – Deadcode

+0

Спасибо, Лирик, и Пер, оба ваши ответы были полезны. – Deadcode