Главная

Популярная публикация

Научная публикация

Случайная публикация

Обратная связь

ТОР 5 статей:

Методические подходы к анализу финансового состояния предприятия

Проблема периодизации русской литературы ХХ века. Краткая характеристика второй половины ХХ века

Ценовые и неценовые факторы

Характеристика шлифовальных кругов и ее маркировка

Служебные части речи. Предлог. Союз. Частицы

КАТЕГОРИИ:






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




http://cs.mipt.ru/docs/courses/osstud/05/ch5.htm - l0502Все рассмотренные в лабораторной работе примеры являются не совсем корректными. В большинстве случаев они работают правильно, однако возможны ситуации, когда совместная деятельность этих процессов или нитей исполнения приводит к неверным и неожиданным результатом. Это связано с тем, что любые неатомарные операции, связанные с изменением содержимого разделяемой памяти, представляют собой критическую секцию процесса или нити исполнения. При одновременном существовании 2-х процессов в операционной системе может возникнуть следующая последовательность выполнения операций во времени:

...

Процесс 1: array[0] += 1;

Процесс 2: array[1] += 1;

Процесс 1: array[2] += 1;

Процесс 1: printf("Program 1 was spawn %d times, program 2 - %d times, total - %d times\n", array[0], array[1], array[2]);

...

Тогда печать будет давать неправильные результаты. Естественно, что воспроизвести подобную последовательность действий практически нереально. Мы не сможем подобрать необходимые времена старта процессов и степень загруженности вычислительной системы. Это проделано в программах04-4 и 04-5. http://cs.mipt.ru/docs/courses/osstud/05/ch5.htm - l0503Как видим, для написания корректно работающих программ необходимо обеспечивать взаимоисключение при работе с разделяемой памятью и, может быть, взаимную очередность доступа к ней

Примеры программ

Программа 04-1

/* Программа 04-1 для иллюстрации работы с разделяемой памятью*/

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

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/shm.h>

#include <stdio.h>

#include <errno.h>

int main()

{

int *array; /* Указатель на разделяемую память */

int shmid; /* IPC дескриптор для области разделяемой памяти */

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

char pathname[] = "06-1a.c"; /* Имя файла, использующееся для генерации ключа. Файл с таким именем должен существовать в текущей директории */

key_t key; /* IPC ключ */

/* Генерируем IPC ключ из имени файла 06-1a.c в текущей директории и номера экземпляра области разделяемой памяти 0 */

if((key = ftok(pathname,0)) < 0){

printf("Can\'t generate key\n");

exit(-1);

}

/* Пытаемся эксклюзивно создать разделяемую память для сгенерированного ключа, т.е. если для этого ключа она уже существует системный вызов вернет отрицательное значение. Размер памяти определяем как размер массива из 3-х целых переменных, права доступа 0666 - чтение и запись разрешены для всех */

if((shmid = shmget(key, 3*sizeof(int), 0666|IPC_CREAT|IPC_EXCL)) < 0){

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

if(errno!= EEXIST){

/* Если по другой причине - прекращаем работу */

printf("Can\'t create shared memory\n");

exit(-1);

} else {

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

if((shmid = shmget(key, 3*sizeof(int), 0)) < 0){

printf("Can\'t 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 либо инициализируем массив, либо увеличиваем соответствующие счетчики */

if(new){

array[0] = 1;

array[1] = 0;

array[2] = 1;

} else {

array[0] += 1;

array[2] += 1;

}

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

printf("Program 1 was spawn %d times, program 2 - %d times, total - %d times\n",

array[0], array[1], array[2]);

if(shmdt(array) < 0){

printf("Can't detach shared memory\n");

exit(-1);

}

return 0;

}

 

Программа 04-2

/* Программа 2 для иллюстрации работы с разделяемой памятью*/

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

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/shm.h>

#include <stdio.h>

#include <errno.h>

intmain()

{

int *array; /* Указатель на разделяемую память */

int shmid; /* IPC дескриптор для области разделяемой памяти */

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

char pathname[] = "06-1a.c"; /* Имя файла, использующееся для генерации ключа. Файл с таким именем должен существовать в текущей директории */

key_t key; /* IPC ключ */

/* Генерируем IPC ключ из имени файла 06-1a.c в текущей директории и номера экземпляра области разделяемой памяти 0 */

if((key = ftok(pathname,0)) < 0){

printf("Can\'t generate key\n");

exit(-1);

}

/* Пытаемся эксклюзивно создать разделяемую память для сгенерированного ключа, т.е. если для этого ключа она уже существует системный вызов вернет отрицательное значение. Размер памяти определяем как размер массива из 3-х целых переменных, права доступа 0666 - чтение и запись разрешены для всех */

if((shmid = shmget(key, 3*sizeof(int), 0666|IPC_CREAT|IPC_EXCL)) < 0){

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

if(errno!= EEXIST){

/* Если по другой причине - прекращаем работу */

printf("Can\'t create shared memory\n");

exit(-1);

} else {

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

if((shmid = shmget(key, 3*sizeof(int), 0)) < 0){

printf("Can\'t 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 либо инициализируем массив, либо увеличиваем соответствующие счетчики */

if(new){

array[0] = 0;

array[1] = 1;

array[2] = 1;

} else {

array[1] += 1;

array[2] += 1;

}

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

printf("Program 1 wasspawn %dtimes, program 2 - %dtimes, total - %dtimes\n",

array[0], array[1], array[2]);

if(shmdt(array) < 0){

printf("Can't detach shared memory\n");

exit(-1);

}

return 0;

}

 

Программа 04-3

/* Программа для иллюстрации работы двух нитей исполненияКаждая нить исполнения просто увеличивает на 1 разделяемую переменную a.

*/

#include <pthread.h>

#include <stdio.h>

int a = 0;

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

/*Ниже следует текст функции, которая будет ассоциирована со 2-м thread'ом*/

void *mythread(void *dummy)/*

Параметр dummy в нашей функции не используется и присутствует только для совместимости типов данных. По той же причине функция возвращает значение void *, хотя это никак не используется в программе.*/

{

pthread_t mythid; /* Для идентификатора нити исполнения */

/*Заметим, что переменная mythidявляется динамической локальной переменной функцииmythread(), т.е. помещается в стеке и, следовательно, не разделяется нитями исполнения. */

/* Запрашиваемидентификаторthread'а */

mythid = pthread_self();

a = a+1;

printf("Thread %d, Calculation result = %d\n", mythid, a);

returnNULL;

}

/*Функцияmain() - онажеассоциированнаяфункцияглавногоthread'а*/

int main()

{

pthread_t thid, mythid;

int result;

/* Пытаемся создать новую нить исполнения, ассоциированную с функцией mythread().Передаем ей в качестве параметра значение NULL.В случае удачи в переменную thid занесется идентификатор нового thread'а. Есливозникнетошибка - прекратимработу. */

result = pthread_create(&thid, (pthread_attr_t *)NULL, mythread, NULL);

if(result!= 0){

printf ("Error on thread create, return value = %d\n", result);

exit(-1);

}

printf("Threadcreated, thid = %d\n", thid);

/*Запрашиваемидентификаторглавногоthread'а */

mythid = pthread_self();

a = a+1;

printf("Thread %d, Calculationresult = %d\n", mythid, a);

/*Ожидаемзавершенияпорожденногоthread'a, неинтересуяськакоезначениеоннамвернет. Если не выполнить вызов этой функции, то возможна ситуация, когда мы завершим функцию main() до того, как выполнится порожденный thread, что автоматически повлечет его завершение,исказив результаты.*/

pthread_join(thid, (void **)NULL);

return 0;

}

 

Программа 04-4

/* Программа 04-4 для иллюстрации некорректности работы с разделяемой памятью*/

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

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/shm.h>

#include <stdio.h>

#include <errno.h>

int main()

{

int *array; /* Указательнаразделяемуюпамять */

intshmid; /* IPC дескриптор для области разделяемой памяти */

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

charpathname[] = "06-1a.c"; /* Имя файла, использующееся для генерации ключа. Файл с таким именем должен существовать в текущей директории */

key_tkey; /* IPCключ */

longi;

/* Генерируем IPC ключ из имени файла 06-1a.c в текущей директории и номера экземпляра области разделяемой памяти 0 */

if((key = ftok(pathname,0)) < 0){

printf("Can\'t generate key\n");

exit(-1);

}

/* Пытаемся эксклюзивно создать разделяемую память для сгенерированного ключа, т.е. если для этого ключа она уже существует, то системный вызов вернет отрицательное значение. Размер памяти определяем как размер массива из 3-х целых переменных, права доступа 0666 - чтение и запись разрешены для всех */

if((shmid = shmget(key, 3*sizeof(int), 0666|IPC_CREAT|IPC_EXCL)) < 0){

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

if(errno!= EEXIST){

/* Если по другой причине - прекращаем работу */

printf("Can\'t create shared memory\n");

exit(-1);

} else {

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

if((shmid = shmget(key, 3*sizeof(int), 0)) < 0){

printf("Can\'t 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 либо инициализируем массив, либо увеличиваем соответствующие счетчики */

if(new){

array[0] = 1;

array[1] = 0;

array[2] = 1;

} else {

array[0] += 1;

for(i=0; i<1000000000L; i++);

/* Предельное значение для i может меняться в зависимости от производительности компьютера */

array[2] += 1;

}

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

printf("Program 1 was spawn %d times, program 2 - %d times, total - %d times\n",

array[0], array[1], array[2]);

if(shmdt(array) < 0){

printf("Can't detach shared memory\n");

exit(-1);

}

return 0;

}

Программа 04-5

/* Программа 04-5 для иллюстрации некорректности работы с разделяемой памятью */

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

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/shm.h>

#include <stdio.h>

#include <errno.h>

int main()

{

int *array; /* Указательнаразделяемуюпамять */

intshmid; /* IPC дескриптор для области разделяемой памяти */

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

charpathname[] = "06-1a.c"; /* Имя файла, использующееся для генерации ключа. Файл с таким именем должен существовать в текущей директории */

key_t key; /* IPC ключ */

longi;

/* Генерируем IPC ключ из имени файла 06-1a.c в текущей директории и номера экземпляра области разделяемой памяти 0 */

if((key = ftok(pathname,0)) < 0){

printf("Can\'t generate key\n");

exit(-1);

}

/* Пытаемся эксклюзивно создать разделяемую память для сгенерированного ключа, т.е. если для этого ключа она уже существует, то системный вызов вернет отрицательное значение. Размер памяти определяем как размер массива из 3-х целых переменных, права доступа 0666 - чтение и запись разрешены для всех */

if((shmid = shmget(key, 3*sizeof(int), 0666|IPC_CREAT|IPC_EXCL)) < 0){

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

if(errno!= EEXIST){

/* Если по другой причине - прекращаем работу */

printf("Can\'t create shared memory\n");

exit(-1);

} else {

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

if((shmid = shmget(key, 3*sizeof(int), 0)) < 0){

printf("Can\'t 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 либо инициализируем массив, либо увеличиваем соответствующие счетчики */

if(new){

array[0] = 0;

array[1] = 1;

array[2] = 1;

} else {

array[1] += 1;

for(i=0; i<1000000000L; i++);

/* Предельное значение для i может меняться в зависимости от производительности компьютера */

array[2] += 1;

}

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

printf("Program 1 was spawn %d times, program 2 - %d times, total - %d times\n",

array[0], array[1], array[2]);

if(shmdt(array) < 0){

printf("Can't detach shared memory\n");

exit(-1);

}

return 0;

}






Не нашли, что искали? Воспользуйтесь поиском:

vikidalka.ru - 2015-2024 год. Все права принадлежат их авторам! Нарушение авторских прав | Нарушение персональных данных