세마포어 관련 함수
기능 함수원형
세마포어 생성 | int semget(key_t key, int nsems, int semflg); |
세마포어 제어 | int semctl(int semid, int semnum, int cmd, ...); |
세마포어 연산 | int semop(int semid, struct sembuf *sops, size_t nsops); |
세마포어 생성: semget(2)
세마포어를 사용하려면 세마포어 식별자를 생성해야 합니다. 세마포어 식별자는 semget 함수를 사용해 생성한다.
#include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> int semget(key_t key, int nsems, int semflg); |
- key: IPC_PRIVATE 또는 ftok 함수로 생성한 키
- nsems: 생성할 세마포어 개수
- semflg: 세마포어 접근 속성
semget 함수는 인자로 키와 생성할 세마포어 개수, 플래그를 받고 세마포어 식별자를 리턴한다.
첫 번째 인자인 key에는 IPC_PRIVATE나 ftok 함수로 생성한 키를 지정한다.
두 번째 인자인 nsems에는 생성할 세마포어의 개수를 지정한다. 세마포어는 집합 단위로 처리되므로, 한 식별자에 여러 세마포어가 생성된다.
세번째 인자인 semflg에는 플래그와 접근 권한을 지정한다. 플래그는 msgget 함수와 마찬가지로 IPC_CREAT와 IPC_EXCL을 사용한다.
세마포어 식별자와 관련된 세마포어와 데이터 구조체가 새로 생성되는 경우는 다음 두가지이다.
- key가 IPC_PRIVATE다.
- key가 0이 아니며 다른 식별자와 관련되어 있지 않고, 플래그(semflg)에 IPC_CREAT가 설정되어 있다.
이 두 가지 경우가 아니면 semget 함수는 기존 세마포어의 식별자를 리턴한다.
세마포어에 관한 정보를 담고 있는 구조체는 semid_ds로, <sys/sem.h>에 다음과 같이 정의되어 있다.
struct semid_ds {
struct ipc_perm sem_perm; // IPC 공통 구조체를 의미한다.
// 세마포어 집합에서 첫번째 세마포어의 주소다.
// sem 구조체는 세마포어 집합에 있는 각 세마포어에 관한 정보를 저장한다.
// sem 구조체는 <sys/sem_impl.h> 파일에 정의되어 있다.
struct sem *sem_base;
ushort_t sem_nsems; // 세마포어 집합의 세마포어 개수다.
time_t sem_otime; // 세마포어 연산을 마지막으로 수행한 시각이다.
int32_t sem_pad1;
time_t sem_ctime; // 세마포어의 접근 권한을 마지막으로 변경한 시각이다.
int32_t sem_pad2;
int sem_binary; // 세마포어의 종류를 나타내는 프래그다.
long sem_pad3[3];
};
struct sem {
ushort_t semval; // 세마포어 값
pid_t sempid; // 세마포어 연산을 마지막으로 수행한 프로세스 ID
ushort_t semncnt; // 세마포어 값이 현재 값보다 증가하기를 기다리는 프로세스 수
ushort_t semzcnt; // 세마포어 값이 0이 되기를 기다리는 프로세스 수
kcondvar_t semncnt_cv;
kcondvar_t semzcnt_cv;
};
새로운 세마포어 식별자를 리턴할 때 구조체는 다음과 같이 설정된다.
- sem_perm.cuid, sem_perm.uid: 함수를 호출한 프로세스의 유효 사용자 ID로 설정된다.
- sem_perm.cgid, sem_perm.gid: 함수를 호출한 프로세스의 유효 그룹 ID로 설정된다.
- sem_perm.mode: semflg 값으로 설정된다.
- sem_nsems: nsems 값으로 설정된다.
- sem_otime: 0으로 설정된다.
- sem_ctime: 현재 시각으로 설정된다.
세마포어 제어: semctl(2)
semctl 함수로 세마포어의 기능을 제어할 수 있습니다.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semctl(int semid, int semnum, int cmd, ...);
- sedmid: semget 함수로 생성한 세마포어 식별자
- semnum: 기능을 제어할 세마포어 번호
- cmd: 수행할 제어 명령
- ...: 제어 명령에 따라 필요시 사용할 세마포어 공용체의 주소(선택 사항)
semctl 함수는 semid로 식별되는 세마포어 집합에서 semnum으로 지정한 세마포어에 cmd로 지정한 제어 기능을 수행합니다. cmd에 따라 선택적으로 네번째 인자가 있을 수 있다.
세 번째 인자인 cmd에 지정할 수 있는 값은 다음과 같다.
- IPC_RMID: semid로 지정한 세마포어와 관련된 데이터 구조체를 제거한다.
- IPC_SET: 세마포어 정보 내용 중 sem_perm.uid, sem_perm.gid, sem_perm.mode 값을 네 번째 인자로 지정한 값으로 변경한다. 이 명령은 root 권한이 있거나 유효 사용자 ID일 경우만 사용할 수 있다.
- IPC_STAT: 현재 세마포어의 정보를 arg.buf로 지정한 메모리에 저장한다.
- GETVAL: 세마포어의 semval 값을 읽어온다.
- SETVAL: 세마포어의 semval 값을 arg.val로 설정한다.
- GETPID: 세마포어의 sempid 값을 읽어온다.
- GETNCNT: 세마포어의 semncnt 값을 읽어온다.
- GETZCNT: 세마포어의 semzcnt 값을 읽어온다.
- GETALL: 세마포어 집합에 있는 모든 세마포어의 semval 값을 arg.array가 가리키는 배열에 저장한다.
- SETALL: 세마포어 집합에 있는 모든 세마포어의 semval 값을 arg.array가 가리키는 배열값으로 설정한다.
semctl 함수의 리턴값은 cmd에 따라 달라진다.
cmd가 GETVAL이면 semval 값을 리턴하고, GETPID면 sempid 값을 리턴한다.
cmd가 GETNCNT면 semncnt 값을 리턴하고, GETZCNT면 semzcnt 값을 리턴한다.
semctl 함수는 수행을 성공하면 0을, 오류가 발생하면 모든 경우에 -1을 리턴한다.
네 번째 인자는 제어 명령에 따른 선택 사항입니다. 네 번째 항목이 필요할 경우 다음과 같은 공용체(union)을 사용한다. 이 공용체는 프로그램에서 명시적으로 선언하고 사용해야 한다다.
union semun {
int val;
struct semid_ds *buf;
ushort_t *array;
} arg;
세마포어 연산: semop(2)
잠금과 해제와 같은 세마포어 연산을 수행하려면 semop 함수를 사용한다.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semop(int semid, struct sembuf *sops, size_t nsops);
- sedmid: semget 함수로 생성한 세마포어 식별자
- sops: sembuf 구조체의 주소
- nsops: sops가 가리키는 구조체의 크기
semop 함수는 semid가 가리키는 세마포어에 크기가 nsops인 sembuf 구조체로 지정한 연산을 실행한다.
sembuf 구조체는 <sys/sem.h> 파일에 정의되어 있다.
struct sembuf {
ushort_t sem_num; // 세마포어 번호를 의미
short sem_op; // 세마포어 연산을 의미
// 연산을 위한 플래그로, IPC_NOWAIT 또는 SEM_UNDO를 지정한다.
// SEM_UNDO: 프로세스가 비정상적으로 갑자기 종료할 때
// 세마포어 동작을 취소한다.
short sem_flg;
};
세마포어 연산은 sembuf 구조체의 sem_op 항목에 지정한다.
sem_op 항목은 semop 함수가 수행할 기능을 정수로 나타내며, 다음과 같은 세 가지 경우가 있다.
if(sem_op < 0) { /* 세마포어 잠금 */
wait until semval >= | sem_op |;
semval -= | sem_op |;
} else if (sem_op > 0) /* 세마포어 잠금 해제 */
semval += sem_op;
else
wait until semval is 0;
1) sem_op가 음수면 세마포어 잠금 기능을 수행한다. 이는 공유 자원을 사용하려는 것이다.
- semval 값이 sem_op의 절댓값과 같거나 크면 semval 값에서 sem_op의 절댓값을 뺀다.
- semval 값이 sem_op 값보다 작고, sem_flg에 IPC_NOWAIT이 설정되어 있으면 semop 함수는 즉시 리턴한다.
- semval 값이 sem_op 값보다 작은데 sem_flg에 IPC_NOWAIT이 설정되어 있지 않으면, semop 함수는 semncnt 값을 증가시키고 다음 상황을 기다린다.
semval 값이 sem_op의 절댓값보다 같거나 커진다. 이 경우 semncnt 값은 감소하고 semval 값에서 sem_op의 절댓값을 뺀다.
시스템에서 semid가 제거된다. 이 경우 errno가 EIDRM으로 설정되고 -1을 리턴한다.
semop 함수를 호출한 프로세스가 시그널을 받는다. 이 경우 semncnt 값은 감소하고 시그널 처리 함수를 수행한다.
2) sem_op가 양수면 이는 세마포어의 잠금을 해제하고, 사용 중이던 공유 자원을 돌려준다. 이 경우 sem_op 값이 semval 값에 더해진다.
3) sem_op 값이 0인 경우
- semval 값이 0이면 semop 함수는 즉시 리턴한다.
- semval 값이 0이 아니고, sem_flg에 IPC_NOWAIT이 설정되어 있으면 semop 함수는 즉시 리턴한다.
- semval 값이 0이 아니고, sem_flg에 IPC_NOWAIT이 설정되어 있지 않으며, semop 함수는 semzcnt 값을 증가시키고 semval 값이 0이 되길 기다린다.
출처: https://12bme.tistory.com/227 [길은 가면, 뒤에 있다.]
Semaphore
'Etc' 카테고리의 다른 글
Database 용어 정리 (0) | 2021.11.17 |
---|---|
[IPC]Shared Memory 응용 (0) | 2021.10.22 |
[IPC]Shared Memory (0) | 2021.10.22 |
[IPC]Semaphore (0) | 2021.10.22 |
[IPC]Semaphore C 예제 (0) | 2021.10.22 |