Intereting Posts
как получить базовое имя сложных файлов Как перенаправить вывод команды в файл? Как восстановить доступ к Интернету? ТОЛЬКО программа, которая по-прежнему пользуется Интернетом – это разнообразие (приложение для обоев) rsyslogd Повторяется HUPed Запуск много последовательных exes с вином, быстрый Совпадение простого регулярного выражения Все ли процессы Linux записывают EOF в stdout, когда они завершают / заканчивают завершение? Загрузите только недавно измененные файлы с помощью wget over FTP Показывать только скрытые файлы (файлы точек) в псевдониме ls Как определить исполняемый путь с его PID на AIX 5 или более Что такое команда, которая отобразит только синтаксис и параметры команды? Как добавить пусковую установку, которая компилирует некоторый код в терминале в XFce? Нет правила для создания target `include / config / auto.conf ', необходимого для` include / config / kernel.release'. Стоп Что такое «цитата»? Тип 1 Гипервизор аппаратных привилегий, используйте драйверы хоста.

Процессор не видит изменений в общей памяти POSIX?

Контекст: я использую разделяемую память POSIX, чтобы обеспечить набор процессов разделяемой памятью. Я использовал эту схему в течение некоторого времени для обмена данными, и она работает хорошо. Однако недавно я столкнулся со странной проблемой с определенным classом программ.

Проблема: я написал программу, в которой каждый процесс должен внести значение в общую сумму в пространстве общей памяти. Сумма была инициализирована нулем, когда общий объект был ранее отображен в памяти. Однако, когда каждый процесс пытается добавить свою часть к общей сумме, он может увидеть последнее значение, но результат добавления всегда такой, как если бы он добавил свое собственное значение с нулем . Увидеть ниже:

[21017] Adding 6 to 0! [21020] Adding 33 to 0! [21016] Adding 15 to 0! [21018] Adding 24 to 0! [21017] Got access! (0x7fe953fcb000 = 0) [21017] Done (0x7fe953fcb000 = 6) [21016] Got access! (0x7fe953fcb000 = 6) [21016] Done (0x7fe953fcb000 = 15) [21018] Got access! (0x7fe953fcb000 = 15) [21018] Done (0x7fe953fcb000 = 24) [21020] Got access! (0x7fe953fcb000 = 24) [21020] Done (0x7fe953fcb000 = 33) Sum = 33 

Каждый процесс «видит» последнее записанное значение, но каким-то образом после добавления своего собственного компонента, похоже, игнорирует существующее значение. Вы можете видеть, что каждый доступ упорядочен последовательно, так как есть система управления доступом, которая управляет тем, кто получает возможность записи в общую область памяти. Используемая тестовая программа выглядит следующим образом (хотя я не ожидаю, что читатель ее запустит):

 int main (void) { int local_sum = 0, gid = -1; volatile int *sum; // Fork for four processes. for (int i = 1; i < 4; i++) { if (fork() == 0) break; } // Initialize the DSM. Set GID. sum = (int *)dsm_init(&cfg); gid = dsm_get_gid(); // Compute range. for (int i = 0; i < 3; i++) { local_sum += array[(gid * 3) + i]; } // Add to local sum. printf("[%d] Adding %d to %d!\n", getpid(), local_sum, *sum); *sum = *sum + local_sum; // Barrier. dsm_barrier(); // Print sum if process zero. if (gid == 0) printf("Sum = %d\n", *sum); // Exit. dsm_exit(); } 

Почему каждый процесс может «видеть» правильное значение по адресу 0x7fe953fcb000 в общем пространстве, но после добавления ведет себя так, как если бы значение по этому адресу во время добавления было по-прежнему нулевым?


Вот что беспокоит меня об этой проблеме:

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

Есть ли какое-то объяснение, почему это может происходить под капотом? Я попытался использовать GDB с моей программой, чтобы увидеть, что происходит. Но, насколько я могу судить, это просто перемещение значения по адресам памяти в регистры. Я пока не вижу проблем с оптимизацией.

Насколько я вижу, четыре процесса порождаются в быстрой последовательности, и каждый из них пытается сделать * sum + = some_value; вполне возможно, что все они видят * сумму как ноль перед сложением.

Давайте использовать абстрактный синтаксис ассемблера. Заявление C

 *sum = *sum + local_sum 

составлен в

 LOAD *sum into R0 LOAD local_sum into R1 ADD R1 to R0 STORE R0 to *sum 

Четыре процесса стремятся выполнить эту последовательность. Вполне возможно, что все они выполняют LOAD * sum для R0, прежде чем кто-либо из них сможет выполнить STORE R0 для * sum; на самом деле, учитывая, что, как вы говорите, существует системный вызов (и, следовательно, точка репланирования), инициируемый STORE R0 для * sum, существует очень хороший шанс. Вам необходимо синхронизировать доступ к общим переменным, например, с помощью семафоров.