Что блокировать и что не блокировать в многопоточной среде (семафоры и разделяемая память) - PullRequest
2 голосов
/ 14 ноября 2010

Я реализовывал простую программу Producer / Consumer, в которой были некоторые семафоры и общая память.Для простоты, давайте предположим, что в моей программе есть только блок разделяемой памяти и семафор.

Сначала я подумал, что мне нужно рассматривать только биты критического раздела, которые будут пытатьсязапись в блок общей памяти.Но поскольку блок разделяемой памяти состоит, скажем, из 1024 байт, я не могу прочитать все данные одновременно (это не атомарная операция), поэтому действительно возможно, что, пока я читаю из него, источникприходит и начинает писать в нем, так что читатель получит половину старых данных, половину новых данных.Исходя из этого, я могу только думать, что мне также нужно поместить логику чтения разделяемой памяти в блок «семафор».

Теперь у меня есть много кода, который выглядит следующим образом:

if (sharedMemory[0] == '0') { ... }

В этом случае я просто ищу один символ в памяти.Я полагаю, мне не нужно беспокоиться о том, чтобы поместить семафор вокруг этого, не так ли?

И что, если вместо этого у меня есть что-то вроде

if (sharedMemory[0] == '0' && sharedMemory[1] == '1') { ... }

С моей точки зрения, я думаю, чтоэто 2 операции, я должен рассматривать это как критическую секцию, поэтому нужно поместить семафор вокруг него.Я прав?

Спасибо!

Ответы [ 2 ]

1 голос
/ 14 ноября 2010

Технически, в многоядерной или многопроцессорной системе единственное, что является атомарным, - это коды операций сборки, которые специально задокументированы как атомарные. Даже чтение одного байта дает (довольно малый) шанс, что другой процессор приедет и изменит его перед тем, как вы начнете его читать, за исключением некоторых случаев, связанных с кэшем ЦП и выровненными фрагментами памяти (Поток забав: http://software.intel.com/en-us/forums/showthread.php?t=76744, Интересно читать: http://www.corensic.com/CorensicBlog/tabid/101/EntryId/8/Memory-Consistency-Models.aspx)

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

(Ответ может немного измениться на платформах IL, таких как .NET и JVM, поскольку они дают свои собственные гарантии относительно того, что является атомарным, а что нет).

1 голос
/ 14 ноября 2010

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

...