Чтение и запись в общую память SysV без синхронизации (использование семафоров, C / C ++, Linux) - PullRequest
1 голос
/ 10 июня 2010

Я использую разделяемую память SysV, чтобы два процесса могли общаться друг с другом. Я не хочу, чтобы код становился сложным, поэтому я подумал, действительно ли мне пришлось использовать семафоры для синхронизации доступа к общей памяти. В моей программе на C / C ++ родительский процесс читает из общей памяти, а дочерний процесс записывает в общую память. Я написал два тестовых приложения, чтобы посмотреть, смогу ли я вызвать какую-то ошибку, такую ​​как ошибка сегментации, но я не смог (Ubuntu 10.04 64bit). Даже два процесса, записывающих безостановочно в цикле while в одну и ту же разделяемую память, не выдавали никакой ошибки.

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

Спасибо

Ответы [ 6 ]

4 голосов
/ 10 июня 2010

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

Предположим, ваш ребенок находится на полпути через запись в общую память, когда он выгружается. Совместно используемая память теперь находится в «плохом» состоянии - часть ее относится к одному состоянию дочернего процесса, а остальное - к предыдущему - и возможно, что ваш родитель может быть реактивирован раньше, чем ребенок. Тогда у вас поврежденное состояние.

Вы , возможно, сможете избежать неприятностей в краткосрочной перспективе, но вы найдете странные ошибки позже.

1 голос
/ 10 июня 2010

В дополнение ко всем хорошим ответам - взгляните на библиотеку boost::interprocess - очень удобно для хранения C ++ STL-подобных контейнеров в разделяемой памяти.Он реализован с разделяемой памятью POSIX в Unixen, а не в SysV, shmem_open(3) и др., Что также может вас заинтересовать.

1 голос
/ 10 июня 2010

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

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

  1. У вас есть только один поток записина указанный адрес.

  2. Записанные данные атомарные - это означает, что они могут быть переданы за одну операцию ввода / вывода.Простые вещи, такие как символы и целые числа, обычно атомные при передаче.Многие структуры, строки и массивы являются НЕ атомарными операциями при копировании, поскольку они часто состоят из нескольких элементов размера ввода / вывода.

  3. Достоверность данныхЭлемент не зависит от какой-либо другой части данных.

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

Если что-либо из вышеперечисленного не выполнено, вы должны использовать какую-либо синхронизацию, если хотите гарантировать, что данные согласованы и действительны.

1 голос
/ 10 июня 2010

Как уже упоминалось, речь идет о целостности данных, а не об ошибках.

Если это проблема, используйте: pipe - простую систему IPC для реализации, может быть, 6 строк кода в родительском, то же самое в дочернем

http://tldp.org/LDP/lpg/node11.html

0 голосов
/ 11 июня 2010

Я бы предложил использовать один флаг для обозначения прав доступа. Подобно тому, как поток писателя создаст флаг - и как только запись завершится, поток писателя может сделать его флагом ++, поток чтения также сделает то же самое.Таким образом, избегайте использования Mutex и блокировки наверху.Я использовал это и, поверьте мне, flag-- и flag ++ в основном атомарны :-)

0 голосов
/ 11 июня 2010

Вот немного другой подход: если вы можете гарантировать, что ваши читатели / писатели не неожиданно вытеснят друг друга, вам не нужно синхронизироваться между ними.

Например,вы можете гарантировать, что в вашем Linux, если вы используете политику планировщика SCHED_FIFO (см. sched_setscheduler(2)) для всех процессов, которые обращаются к вашей общей памяти, И если они работают с тем же приоритетом в реальном времени И все они заблокированы для одного и того жеЯдро процессора (в многоядерных системах).Затем, если читатель выполняет, он будет единственным процессом, выполняющимся до тех пор, пока он не решит подождать какое-либо условие или неактивен по таймеру.Даже если писатель выйдет из состояния, в котором он ожидал, во время чтения планировщик не разрешит автору работать до тех пор, пока не будет завершено чтение.

...