Process synchronization
- 다중 프로그래밍 시스템
- 여러 개의 프로세스들이 존재
- 프로세스들은 서로 독립적으로 동작
- 공유 자원 또는 데이터가 있을 때, 문제 발생 가능
- 동기화
- 프로세스들이 서로 동작을 맞추는 것
- 프로세스들이 서로 정보를 공유하는 것
Mutaul exclusion primitives
- enterCS()
- Critical section 진입 전 검사
- 다른 프로세스가 critical section안에 있는지 검사
- exitCS()
- critical section을 벗어날 때의 후처리 과정
- critical section을 벗어남을 시스템이 알림
Semaphore
- 1965년 Dijkstra가 제안
- Busy waiting 문제 해결
- 음이 아닌 정수형 변수(S)
- 초기화 연산, P(), V()로만 접근 가능
- P: Probern(검사)
- V: Verhogen(증가)
- 임의의 S 변수 하나에 ready queue 하나가 할당됨
- Binary semaphore
- S가 0과 1 두 종류의 값만 갖는 경우
- 상호배제나 프로세스 동기화의 목적으로 사용
- Counting semaphore
- S가 0이상의 정수 값을 가질 수 있는 경우
- Producer-Consumer 문제 등을 해결하기 위해 사용
creating a semaphore array
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
- key : IPC key
- nsems : 생성할 semaphore 변수 수
- 하나의 identifier에 여러 개의 변수 생성 가능
- semflg : 생성 방법 및 접근 권한
- return : 생성된 semaphore 객체의 identifier
operating on a semaphore
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semop(int semid, struct sembuf* sops, size_t nsops);
- semid : semaphore ID
- sops : sembuf 구조체 배열
- sembuf : 수행할 명령을 담은 구조체
- 순서대로 실행됨
- nsops : sops가 가리키는 구조체의 수
- return
controlling a semaphore
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semctl(int semid, int semnum, int cmd, ...);
- semid : semaphore array ID
- semnum : 제어할 semaphore의 번호
- cmd : 수행할 제어기능
- IPC_STAT, IPC_RMID
- GETVAL, SETVAL, GETPID, GETNCNT, GETZCNT
- ... : cmd에 따라 용도가 지정됨
- return
Example
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
union semun {
int val;
struct semid_ds* buf;
unsigned short* array;
};
int initsem(key_t semkey) {
union semun semunarg;
int status = 0, semid;
semid = semget(semkey, 1, IPC_CREAT | IPC_EXCL | 0600);
if (semid == -1) {
if (errno == EEXIST)
semid = semget(semkey, 1, 0);
}
else {
semunarg.val = 1;
status = semctl(semid, 0, SETVAL, semunarg);
}
if (semid == -1 || status == -1) { perror("initsem"); return (-1); }
return semid;
}
int semlock(int semid) {
struct sembuf buf;
buf.sem_num = 0;
buf.sem_op = -1; // P
buf.sem_flg = SEM_UNDO;
if (semop(semid, &buf, 1) == -1) {
perror("semlock failed");
exit(1);
}
return 0;
}
int semunlock(int semid) {
struct sembuf buf;
buf.sem_num = 0;
buf.sem_op = 1; // V
buf.sem_flg = SEM_UNDO;
if (semop(semid, &buf, 1) == -1) {
perror("semunlock failed");
exit(1);
}
return 0;
}
void semhandle() {
int semid;
pid_t pid = getpid();
if ((semid = initsem(1)) < 0) exit(1);
semlock(semid);
printf("Lock : Process %d\n", (int)pid); // critical
printf("** Lock Mode : Critical Section\n"); // section
sleep(1); // critical
printf("Unlock : Process %d\n", (int)pid); // section
semunlock(semid);
exit(0);
}
int main(void) {
int a;
for (a = 0; a < 3; a++)
if (fork() == 0) semhandle();
return 0;
}