<<
>>

Необходимость синхронизации процессов и нитей исполнения, использующих общую память

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

Вернемся к рассмотрению программ из раздела «Прогон программ с использованием разделяемой памяти». При одновременном существовании двух процессов в операционной системе может возникнуть следующая последовательность выполнения операций во времени:

program 2 - %d times, total - %d times\n", array[0], array[1], array[2]);

Тогда печать будет давать неправильные результаты.

Естественно, что воспроизвести подобную последовательность действий практически нереально. Мы не сможем подобрать необходимое время старта процессов и степень загруженности вычислительной системы. Но мы можем смоделировать эту ситуацию, добавив в обе программы достаточно длительные пустые циклы перед оператором array [2 ] + = 1; Это проделано в следующих программах:

/* Программа 1 (06-За.с) для иллюстрации

некорректной работы с разделяемой памятью */

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

#include

#include

#include

#include

#include int main()

{

int *array; /* Указатель на разделяемую память */ int shmid; /* IPC-дескриптор для области разделяемой памяти */

int new = 1; /* Флаг необходимости инициализации

элементов массива */

char pathname!] = "06-За.с"; /* Имя файла,

использующееся для генерации ключа. Файл с таким именем должен существовать в текущей директории */ key_t key; /* IPC-ключ */ long i;

/* Генерируем IPC-ключ из имени файла 06-За.с в текущей директории и номера экземпляра области разделяемой памяти 0 */ if((key = ftok(pathname,0)) < 0){

printf ("Can\ ' t generate keyin'');

exit(-1);

}

/* Пытаемся эксклюзивно создать разделяемую память для сгенерированного ключа, т.

е. если для этого ключа она уже существует, системный вызов вернет отрицательное значение. Размер памяти определяем как размер массива из трех целых переменных, права доступа 0666 - чтение и запись разрешены для всех */ if((shmid = shmget(key, 3*sizeof(int),

О666 I IPC_CREATI IPC_EXCL) ) < 0){

/* В случае возникновения ошибки пытаемся определить: возникла ли она из-за того, что сегмент разделяемой памяти уже существует или по другой причине */ if(errno != EEXIST){

/* Если по другой причине - прекращаем работу */ printf("Can\'t create shared memoryXn"); exit ( -1) ;

} else {

/* Если из-за того, что разделяемая память уже существует - пытаемся получить ее IPC- дескриптор и, в случае удачи, сбрасываем флаг необходимости инициализации элементов массива */

if((shmid = shmget(key, 3*sizeof(int), 0)) < 0){ printf("Can\1t find shared memory\n"); exit(-1);

}

new = 0;

}

}

/* Пытаемся отобразить разделяемую память в адресное пространство текущего процесса. Обратите внимание на то, что для правильного сравнения мы явно преобразовываем значение -1 к указателю на целое.*/ if((array = (int *)shmat(shmid, NULL, 0)) ==

(int *)(-1)){

printf("Can't attach shared memory\n"); exit(-1);

}

/* В зависимости от значения флага new либо инициализируем массив, либо увеличиваем соответствующие счетчики */

= 1; = 0; = 1;

+ = 1 ;

i

<< | >>
Источник: В.Е. Карпов К.А. Коньков. Основы операционных систем. 2005

Еще по теме Необходимость синхронизации процессов и нитей исполнения, использующих общую память:

  1. 9.5. ПАМЯТЬ - НЕОБХОДИМЫЙ МЕТАНАВЫК
  2. ж) Совершение преступления при нарушении условий пра-вомерности необходимой обороны, задержания лица, со-вершившего преступление, крайней необходимости, обосно-ванного риска, исполнения приказа или распоряжения
  3. Синхронизация
  4. Память прошлого и память будущего
  5. § 19 Уклонение от исполнения. – Право отказываться от исполне- ния за неисправностью другой стороны. – Невозможность исполнения вследствие внешних обстоятельств. – Взаимный отказ от исполнения.
  6. § 1 Общее понятие о договорах и обязательствах. – Сущность прав по обязательствам и отличие от вещных прав. – Значение обязательств в составе имущества. – Разделение учения об обязательствах на общую и особенную часть.
  7. Очерк 2: Берт «Процесс — вот мое достояние. Именно процесс создает успех»
  8. Статья 118. Умышленное убийство при превышении пределов необходимой обороны или при превышении мер, необходимых для задержания преступника
  9. Статья 124. Умышленное причинение тяжких телесных повреждений при превышении пределов необходимой обороны или при превышении мер, необходимых для задержания преступника
  10. 3.6. ИСПОЛЬЗУЙТЕ ТОЛЬКО НАСТОЯЩЕЕ ВРЕМЯ
  11. 4.2.2. Используйте или потеряете
  12. 3. Используйте имя Бога
  13. Используйте имя Бога.
  14. Используйте дуальные перспективы.
  15. ПАМЯТЬ: КЛАССИФИКАЦИЯ
  16. ЧТОБЫ СТАТЬ БОГАТЫМ, ИСПОЛЬЗУЙТЕ СИЛУ ВООБРАЖЕНИЯ
  17. ПАМЯТЬ КРАТКОВРЕМЕННАЯ
  18. 3 Используйте активное программирование, «подключая» к работе голос и движение.