Guest User

Semaphore interlock

a guest
Oct 28th, 2016
338
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 7.11 KB | None | 0 0
  1. /// Демо. Применение массива семафоров в качестве мьютекса для синхронизации
  2. /// нескольких процессов. Если процесс закрывается, захватив ресурс, то
  3. /// ресурс автоматически освобождается, а остальные процессы продолжают свою
  4. /// нормальную работу.
  5. /// Victor Sizov, 28.10.2016
  6.  
  7. // Использование:
  8. // 1. Сначала запустить с одним любым параметром
  9. //      seminterlock 1
  10. //    Это создаст массив семафоров и назначит начальное значение семафору.
  11. //    Можно запускать с параметром много раз, новый семафор не создастся, но
  12. //    снова установится значение семафора.
  13. // 2. Затем выполнить несколько раз
  14. //      seminterlock &
  15. //
  16. // Результат выполнения:
  17. // ...
  18. // [22201] Unlock.
  19. // [22202] Lock 5 sec.
  20. // [22201] Wait...
  21. // [22202] Unlock.
  22. // [22203] Lock 5 sec.
  23. // [22202] Wait...
  24. // ...
  25. // [22203] Unlock.
  26. // [22199] Lock 5 sec. (как увидели эту строчку, сразу kill -TERM 22199).
  27. // [22203] Wait...
  28. // [22200] Lock 5 sec. (ресурс освободился и его сразу занял другой процесс)
  29. // ...
  30. //
  31.  
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <unistd.h>
  35. #include <time.h>
  36. #include <sys/types.h>
  37. #include <sys/ipc.h>
  38. #include <sys/sem.h>
  39. #include <fcntl.h>
  40. #include <stdbool.h>
  41.  
  42. #define DEF_LOCK_TIME 5 // Секунды, время на которое процесс занимает ресурс.
  43.  
  44. /// IPC semaphore mutex ////////////////////////////////////////////////////////
  45.  
  46. int SemID;
  47.  
  48. void DoInit(int argc, char *argv[])
  49. {
  50.     key_t Key;
  51.  
  52.     argv = argv; // Подавление сообщения компилятора о неиспользуемой переменной.
  53.  
  54.     Key = ftok(".", 'i'); // Создать "ключ" для идентификации в OS.
  55.     // В боевых условия, что бы у разных программ получился один и тот же ключ,
  56.     // надо что бы реально существовал файл, передаваемый первым параметром,
  57.     // файл не должен меняться, иначе ключ сформруется другой.
  58.     // Второй параметр то же должен быть одинаковым.
  59.     if (Key < 0)
  60.     {
  61.         perror("ftok");
  62.         exit(1);
  63.     };
  64.  
  65.     if (argc > 1)
  66.     {   // Создать массив семафоров (1 семафор в массиве) и выйти.
  67.         // После создания, перед первым использованием, необходимо правильно
  68.         // установить занчение семафора, т.к. он создастся "заблокированным".
  69.         SemID = semget(Key, 1, IPC_CREAT|S_IRWXO|S_IRWXG|S_IRWXU);
  70.         if (SemID < 0)
  71.         {
  72.             perror("semget");
  73.             exit(1);
  74.         };
  75.         printf("Create IPC semaphore, key = 0x%x\n", Key);
  76.         // Установить начальное значение семафора = 1 (не блокировано).
  77.         semctl(SemID, 0, SETVAL, 1);
  78.         printf("Exit.\n");
  79.         exit(0);
  80.     }
  81.     else
  82.     {   // Использовать ранее созданный семафор.
  83.         SemID = semget(Key, 1, S_IRWXO|S_IRWXG|S_IRWXU);
  84.         if (SemID < 0)
  85.         {
  86.             perror("semget");
  87.             exit(1);
  88.         };
  89.     };
  90. }
  91.  
  92. // Захватиать ресурс. Если ресурс занят, то процесс будет ждать освобожения.
  93. void DoLock(void)
  94. {
  95.     struct sembuf SemBuf;
  96.  
  97.     SemBuf.sem_flg = SEM_UNDO; // SEM_UNDO позволяет OS освободить семафор,
  98.                                // если процесс будет завершен.
  99.     SemBuf.sem_num = 0; // Номер семафора в массиве. Один и его номер 0.
  100.     SemBuf.sem_op = -1; // Операция: "попробовать вычесть 1". Вычесть 1 удастся
  101.                         // если значение семафора больше нуля. А если семафор
  102.                         // равен нулю, то процесс будет ждать, пока не появится
  103.                         // возможность вычесть 1.
  104.     semop(SemID, &SemBuf, 1); // Выполнение.
  105.  
  106.     // Если требуется ждать не вечно, а некоторое время, то нужно использовать
  107.     // semtimedop() вместо semop(), с указанием времени ожидания.
  108.     //
  109.     // struct timespec TimeSpec;
  110.     //
  111.     // TimeSpec.tv_sec = 5; // Ждать 5 секунд.
  112.     // TimeSpec.tv_nsec = 0;
  113.     // semtimedop(SemID, &SemBuf, 1, &TimeSpec);
  114. }
  115.  
  116. // Освободить ресурс.
  117. void DoUnLock(void)
  118. {
  119.     struct sembuf SemBuf;
  120.  
  121.     SemBuf.sem_flg = SEM_UNDO;
  122.     SemBuf.sem_num = 0;
  123.     SemBuf.sem_op = 1; // Увеличить семафор на 1.
  124.     semop(SemID, &SemBuf, 1);
  125. }
  126.  
  127. // Освобождение системных ресурсов, разрушение объектов.
  128. void DoFree(void)
  129. {
  130.     // В боевых условиях, нет необходимости удалять массив семафоров, т.к.
  131.     // им пользуется несколько программ. Есть консольные программы для ручного
  132.     // управления семафорами и другими компонентами подсистемы "IPC" (inter
  133.     // process communication, межпроцессное взаимодействие) .
  134.     // 1) Посмотреть семафоры:
  135.     //      ipcs -s (наш массив семафоров с ключем key, выведенном при создании).
  136.     // 2) Удалить:
  137.     //      ipcrm -S <key> (удалить по key).
  138.     //      ipcrm -s <semid> (удалить по semid, удобнее, т.к. он короче).
  139.  
  140.     // Остается только 1 нюанс. Если в процессе работы удалить массив семафоров,
  141.     // то семафор станет "свободным" и все программы сразу разблокируются.
  142.  
  143.     return;
  144. }
  145.  
  146. /// Main ///////////////////////////////////////////////////////////////////////
  147.  
  148. int main(int argc, char *argv[])
  149. {
  150.     DoInit(argc, argv);
  151.     while (true)
  152.     {
  153.         printf("[%i]\tWait...\n", getpid());
  154.         DoLock();
  155.         printf("[%i]\tLock %d sec.\n", getpid(), DEF_LOCK_TIME);
  156.         sleep(DEF_LOCK_TIME);
  157.         printf("[%i]\tUnlock.\n", getpid());
  158.         DoUnLock();
  159.     };
  160.     DoFree();
  161.     return 0;
  162. }
Advertisement
Add Comment
Please, Sign In to add comment