вопрос безопасности потока - PullRequest
4 голосов
/ 01 марта 2010

Простая ситуация здесь, Если у меня есть три потока, и один для оконного приложения, и я хочу, чтобы они вышли когда оконное приложение закрыто, так ли это потокобезопасно, если я использую одну глобальную переменную, так что три потока выйдут, если только глобальная переменная верна, иначе продолжите свою работу? Волатильное помогает в этой ситуации? Программирование на С ++.

Ответы [ 5 ]

4 голосов
/ 01 марта 2010

Теоретически, volatile недостаточно. Есть два уровня абстракции:

  • между действиями исходного кода и фактическими кодами операций;
  • между тем, что видит ядро ​​/ процессор, и тем, что видят другие ядра / процессоры.

Компилятор может кэшировать данные в регистре и изменять порядок чтения и записи. Используя volatile, вы указываете компилятору создавать коды операций, которые выполняют чтение и запись точно в порядке, указанном в исходном коде. Но это касается только первого слоя. Аппаратная система, которая управляет связью между ядрами процессора, может также задерживать и изменять порядок чтения и записи.

Так получилось, что на оборудовании x86 ядра распространяют записи в основную память довольно быстро, а другие ядра автоматически уведомляются об изменении памяти. Так что volatile кажется достаточным: он гарантирует, что компилятор не будет играть в забавные игры с регистрами, а система памяти достаточно любезна, чтобы справиться с этим вопросом. Обратите внимание, что это не так во всех системах (я думаю, что по крайней мере некоторые системы Sparc могут задерживать распространение записи из-за произвольных задержек - возможно, часов), и я прочитал в одном из руководств AMD, что AMD явно оставляет за собой право на Распространение пишет менее быстро в некоторых будущих процессорах.

Таким образом, чистое решение - использовать мьютекс (pthread_mutex_lock() в Unix, EnterCriticalSection() в Windows) при каждом обращении к вашей глобальной переменной (как для чтения, так и для записи). Примитивы Mutex включают специальную операцию, известную как барьер памяти , которая похожа на volatile на стероидах (она действует как volatile для обоих уровней абстракции).

3 голосов
/ 01 марта 2010

Если вы хотите только «прочитать» переменную общего доступа из других потоков, тогда все нормально в описанной вами ситуации.

Да, требуется volatile подсказка, иначе компилятор может «оптимизировать» переменную.

Ожидание завершения потоков (т. Е. join) также было бы хорошо: таким образом, любая очистка (выполняемая приложением) должна иметь место.

1 голос
/ 01 марта 2010

Нет, это рискованно из-за проблем видимости памяти . На мультипроцессоре запись в память на одном процессоре не означает, что другой процессор сразу увидит это изменение. Кроме того, без использования мьютекса, вполне возможно, что пройдет довольно много времени, прежде чем изменение будет распространено на другие процессоры.

0 голосов
/ 01 марта 2010

Это безопасно, вплоть до того момента, когда вы измените значение переменной, чтобы заставить потоки выйти. На этом этапе 1) вам нужно синхронизировать доступ, и 2) вам нужно что-то сделать (извините, volatile недостаточно), чтобы убедиться, что новое значение правильно передается другим потокам.

Первая часть довольно проста. Последнее существенно сложнее - до такой степени, что вам почти наверняка понадобится какой-то механизм, предоставляемый библиотекой или ОС.

0 голосов
/ 01 марта 2010

Да, это обычная техника.

Но вам также следует дождаться выхода всех дочерних потоков, прежде чем основной поток выйдет из main ().
В большинстве реализаций потоков, если основной поток выходит из main (), все текущие текущие дочерние потоки повторяются (подробности см. В документации по потокам), не позволяя правильно разматывать их стеки. Таким образом, все хорошие преимущества RAII будут потеряны.

Итак, задайте глобальную переменную, но затем подождите (большинство потоковых систем имеют метод соединения, позволяющий дождаться смерти потоков в незанятом состоянии), пока все дочерние элементы завершатся корректно, прежде чем разрешить поток main (). выйти.

...