Linux C: синхронизировать основной процесс с несколькими другими процессами при чтении из общей памяти - PullRequest
0 голосов
/ 05 марта 2020

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

Затем выполняется основной процесс через общую память, объединяя отдельные обновления состояния в одно полное (также каждые две секунды).

У меня запущено два 30 процессов, и иногда полные значения, которые я получаю, не совпадают с двумя второй таймфрейм (возможно, потому что некоторые процессы не могли точно записывать свои данные каждые 2 с).

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

Как этого достичь?

1 Ответ

1 голос
/ 05 марта 2020

Один из многих возможных подходов заключается в использовании операций atomi c для создания глобальной блокировки (чтения) и семафора / счетчика записи.

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

/* supports up to 255 parallel processes. Use uint16_t for more. */
struct { _Atomic uint8_t writing_counter; _Atomic uint8_t lock; } sync_ = {0};

Каждое обновление будет выглядеть примерно так (псевдокод):

_Atomic uint16_t lock = atomic_xchange(&sync_.lock, 1);
if(lock){
   goto reschedule;       /* reschedule the update attempt */
}
atomic_fetch_add(&sync_.writing_counter, 1); /* increase writing counter */
atomic_xor_fetch(&sync_.lock, 1); /* release lock */
/* update */
/* ... */
atomic_fetch_sub(&sync_.writing_counter, 1); /* decrease writing counter */

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

_Atomic uint16_t lock = atomic_xchange(&sync_.lock, 1);
if(lock){
   goto reschedule;                  /* reschedule the update attempt */
}
if(atomic_load(&sync_.writing_counter)){
   atomic_xor_fetch(&sync_.lock, 1); /* unlock before rescheduling */
   goto reschedule;                  /* reschedule the update attempt */
}
/* collect data (be quick, because this is a critical section) */
/* ... */
atomic_xor_fetch(&sync_.lock, 1); /* release lock */

Опять же, есть много других способов сделать это. Это действительно зависит от того, что вам действительно нужно.

...