Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /// Демо. Применение массива семафоров в качестве мьютекса для синхронизации
- /// нескольких процессов. Если процесс закрывается, захватив ресурс, то
- /// ресурс автоматически освобождается, а остальные процессы продолжают свою
- /// нормальную работу.
- /// Victor Sizov, 28.10.2016
- // Использование:
- // 1. Сначала запустить с одним любым параметром
- // seminterlock 1
- // Это создаст массив семафоров и назначит начальное значение семафору.
- // Можно запускать с параметром много раз, новый семафор не создастся, но
- // снова установится значение семафора.
- // 2. Затем выполнить несколько раз
- // seminterlock &
- //
- // Результат выполнения:
- // ...
- // [22201] Unlock.
- // [22202] Lock 5 sec.
- // [22201] Wait...
- // [22202] Unlock.
- // [22203] Lock 5 sec.
- // [22202] Wait...
- // ...
- // [22203] Unlock.
- // [22199] Lock 5 sec. (как увидели эту строчку, сразу kill -TERM 22199).
- // [22203] Wait...
- // [22200] Lock 5 sec. (ресурс освободился и его сразу занял другой процесс)
- // ...
- //
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <time.h>
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/sem.h>
- #include <fcntl.h>
- #include <stdbool.h>
- #define DEF_LOCK_TIME 5 // Секунды, время на которое процесс занимает ресурс.
- /// IPC semaphore mutex ////////////////////////////////////////////////////////
- int SemID;
- void DoInit(int argc, char *argv[])
- {
- key_t Key;
- argv = argv; // Подавление сообщения компилятора о неиспользуемой переменной.
- Key = ftok(".", 'i'); // Создать "ключ" для идентификации в OS.
- // В боевых условия, что бы у разных программ получился один и тот же ключ,
- // надо что бы реально существовал файл, передаваемый первым параметром,
- // файл не должен меняться, иначе ключ сформруется другой.
- // Второй параметр то же должен быть одинаковым.
- if (Key < 0)
- {
- perror("ftok");
- exit(1);
- };
- if (argc > 1)
- { // Создать массив семафоров (1 семафор в массиве) и выйти.
- // После создания, перед первым использованием, необходимо правильно
- // установить занчение семафора, т.к. он создастся "заблокированным".
- SemID = semget(Key, 1, IPC_CREAT|S_IRWXO|S_IRWXG|S_IRWXU);
- if (SemID < 0)
- {
- perror("semget");
- exit(1);
- };
- printf("Create IPC semaphore, key = 0x%x\n", Key);
- // Установить начальное значение семафора = 1 (не блокировано).
- semctl(SemID, 0, SETVAL, 1);
- printf("Exit.\n");
- exit(0);
- }
- else
- { // Использовать ранее созданный семафор.
- SemID = semget(Key, 1, S_IRWXO|S_IRWXG|S_IRWXU);
- if (SemID < 0)
- {
- perror("semget");
- exit(1);
- };
- };
- }
- // Захватиать ресурс. Если ресурс занят, то процесс будет ждать освобожения.
- void DoLock(void)
- {
- struct sembuf SemBuf;
- SemBuf.sem_flg = SEM_UNDO; // SEM_UNDO позволяет OS освободить семафор,
- // если процесс будет завершен.
- SemBuf.sem_num = 0; // Номер семафора в массиве. Один и его номер 0.
- SemBuf.sem_op = -1; // Операция: "попробовать вычесть 1". Вычесть 1 удастся
- // если значение семафора больше нуля. А если семафор
- // равен нулю, то процесс будет ждать, пока не появится
- // возможность вычесть 1.
- semop(SemID, &SemBuf, 1); // Выполнение.
- // Если требуется ждать не вечно, а некоторое время, то нужно использовать
- // semtimedop() вместо semop(), с указанием времени ожидания.
- //
- // struct timespec TimeSpec;
- //
- // TimeSpec.tv_sec = 5; // Ждать 5 секунд.
- // TimeSpec.tv_nsec = 0;
- // semtimedop(SemID, &SemBuf, 1, &TimeSpec);
- }
- // Освободить ресурс.
- void DoUnLock(void)
- {
- struct sembuf SemBuf;
- SemBuf.sem_flg = SEM_UNDO;
- SemBuf.sem_num = 0;
- SemBuf.sem_op = 1; // Увеличить семафор на 1.
- semop(SemID, &SemBuf, 1);
- }
- // Освобождение системных ресурсов, разрушение объектов.
- void DoFree(void)
- {
- // В боевых условиях, нет необходимости удалять массив семафоров, т.к.
- // им пользуется несколько программ. Есть консольные программы для ручного
- // управления семафорами и другими компонентами подсистемы "IPC" (inter
- // process communication, межпроцессное взаимодействие) .
- // 1) Посмотреть семафоры:
- // ipcs -s (наш массив семафоров с ключем key, выведенном при создании).
- // 2) Удалить:
- // ipcrm -S <key> (удалить по key).
- // ipcrm -s <semid> (удалить по semid, удобнее, т.к. он короче).
- // Остается только 1 нюанс. Если в процессе работы удалить массив семафоров,
- // то семафор станет "свободным" и все программы сразу разблокируются.
- return;
- }
- /// Main ///////////////////////////////////////////////////////////////////////
- int main(int argc, char *argv[])
- {
- DoInit(argc, argv);
- while (true)
- {
- printf("[%i]\tWait...\n", getpid());
- DoLock();
- printf("[%i]\tLock %d sec.\n", getpid(), DEF_LOCK_TIME);
- sleep(DEF_LOCK_TIME);
- printf("[%i]\tUnlock.\n", getpid());
- DoUnLock();
- };
- DoFree();
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment