세마포어는 Message queue, Share memory의 프로세스간 메시지 전송의 목적과는 다르게 프로세스간 데이터를 동기화하고 보호하는데 목적이 있습니다.
커널에서 세마포어 정보를 유지하기위해 관리하는 구조체입니다.
이 구조는 semid_ds 유형 이며 다음과 같이 <sys/sem.h> 에 정의되어 있습니다.
/* 시스템의 각 세마포 세트에 대한 하나의 semid 데이터 구조. */
struct semid_ds {
struct ipc_perm sem_perm; /* Ownership and permissions */
time_t sem_otime; /* Last semop time */
time_t sem_ctime; /* Last change time */
unsigned long sem_nsems; /* No. of semaphores in set */
}
sem_perm
이것은 linux/ipc.h 에 정의된 ipc_perm 구조 의 인스턴스입니다.
여기에는 액세스 권한 및 세트 생성자에 대한 정보(uid 등)를 포함하여 세마포어 세트에 대한 권한 정보가 포함됩니다.
-> (세마포어 구조체에 접근할 수 있는 사용자 권한 설정)
sem_otime
마지막 semop() 작업 시간(자세한 내용은 잠시 후)
sem_ctime
이 구조에 대한 마지막 변경 시간(모드 변경 등)
sem_nsems
세마포어 세트(배열)의 세마포어 수
semid_ds 구조 에는 세마포어 배열 자체의 베이스에 대한 포인터가 있습니다.
각 배열 구성원은 sem 구조 유형 입니다. linux/sem.h 에도 정의되어 있습니다.
/* One semaphore structure for each semaphore in the system. */
struct sem {
short sempid; /* pid of last operation */
ushort semval; /* current value */
ushort semncnt; /* num procs awaiting increase in semval */
ushort semzcnt; /* num procs awaiting semval = 0 */
};
sem_pid
마지막 작업을 수행한 PID(프로세스 ID)
sem_semval
세마포어의 현재 값
sem_semncnt
리소스를 사용할 수 있기를 기다리는 프로세스 수
sem_semzcnt
리소스 사용률 100%를 기다리는 프로세스 수
이 시스템 호출은 System V 세마포어 세트를 생성하거나 할당합니다.
커널은 semget 를 통해 넘어온 정보를 이용해서 semid_ds 구조체를 세팅합니다.
int semget(key_t key, int nsems, int semflg);
IPC_EXCL은 그 자체로는 쓸모가 없지만 IPC_CREAT 와 결합하면 기존 세마포 세트가 액세스를 위해 열리지 않도록 보장하는 기능으로 사용할 수 있습니다.
세트의 세마포어의 최대 수는 ``linux/sem.h''에 다음과 같이 정의되어 있습니다:
#define SEMMSL 32 /* <=512 ID당 최대 세마포 수 */
기존 세트를 명시적 으로 여는 경우 nsems 인수는 무시됩니다 .
반환값: 성공 시 세마포어 세트 IPC 식별자
오류 시 -1 : errno
이 시스템 호출은 System V 세마포어 세트에서 리소스 할당, 리소스 대기 또는 리소스 해제 작업을 수행합니다.
int semop(int semid, struct sembuf *sops, size_t nsops);
RETURNS: 성공 시 0(모든 작업 수행)
오류 시 -1 : errno
에러 값
sops가 가리키는 배열의 각 nsops 요소는 단일 세마포어에서 수행할 작업을 지정하는 구조입니다.
unsigned short sem_num; /* semaphore number */
short sem_op; /* semaphore operation */
short sem_flg; /* operation flags */
flag 옵션에 IPC_NOWAIT을 주어 이미 세마포어 lock이 걸려있다면 에러 발생 가능. 0을 주면 unlock까지 대기
sem_num
처리하려는 세마포어의 번호
sem_op
수행할 작업(양수, 음수 또는 0)
sem_flg
운영 플래그
sem_flg에서 인식되는 플래그는 IPC_NOWAIT 및 SEM_UNDO입니다.
작업이 SEM_UNDO를 지정하면 프로세스가 종료될 때 자동으로 취소됩니다.
sops에 포함된 일련의 작업은 배열 순서로 수행되며 원자적으로 수행됩니다. 즉, 작업이 완전한 단위로 수행되거나 전혀 수행되지 않습니다. 모든 작업을 즉시 수행할 수 없는 경우 시스템 호출의 동작은 아래에 설명된 대로 개별 sem_flg 필드에 IPC_NOWAIT 플래그가 있는지에 따라 달라집니다.
각 작업은 세마포어 집합의 sem_num 번째 세마포어에서 수행되며, 집합의 첫 번째 세마포어는 0으로 번호가 매겨집니다. sem_op 값으로 구분되는 세 가지 유형의 작업이 있습니다.
sem_op 이 음수 이면 해당 값을 세마포어에서 뺍니다. 이는 세마포어가 액세스를 제어하거나 모니터링하는 리소스를 얻는 것과 관련이 있습니다. IPC_NOWAIT가 지정되지 않은 경우 호출 프로세스는 세마포어에서 요청된 리소스 양을 사용할 수 있을 때까지 휴면합니다(다른 프로세스가 일부를 해제함).
sem_op이 양수 이면 해당 값이 세마포어에 추가됩니다. 이는 애플리케이션의 세마포어 세트로 리소스를 다시 반환하는 것과 관련이 있습니다. 리소스는 더 이상 필요하지 않을 때 항상 세마포 세트로 반환되어야 합니다!
sem_op 가 0이면 호출 프로세스는 세마포어의 값이 0이 될 때까지 sleep()합니다. 이는 세마포어가 100% 활용도에 도달할 때까지 기다리는 것과 관련이 있습니다. 이에 대한 좋은 예는 전체 사용률에 도달할 경우 세마포 세트의 크기를 동적으로 조정할 수 있는 수퍼유저 권한으로 실행되는 데몬입니다.
세마포어세트에서 제어하는 작업을 수행합니다.
int semctl ( int semid, int semnum, int cmd, union semun arg );
세마포어는 실제로 단일 엔터티가 아니라 집합으로 구현됩니다.
세마포어 작업에서 IPC 키 뿐만 아니라 세트 내의 대산 세마포어도 전달해야합니다.
반환값: 성공 시 양의 정수
오류 시 -1: errno
IPC_INFO, SEM_INFO, SEM_STAT : 세마포어별로 가장 많이 사용된 항목의 인덱스 또는 식별자를 반환
GETNCNT : semncnt 값 반환
GETPID : sempid 값 반환
GETVAL : semval 값 반환
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가 가리키는 배열값으로 설정한다.
cmd 설정 값에 따라서 리턴하는 값이 달라집니다.
GETVAL이면 semval 값을 리턴하고, GETPID면 sempid 값을 리턴합니다.
semctl 함수는 수행을 성공하면 0을, 오류가 발생하면 모든 경우에 -1을 리턴합니다.
arg 인수 는 semun 유형의 인스턴스를 나타냅니다 . 이 특정 공용체는 다음과 같이 linux/sem.h 에서 선언됩니다 .
/* semctl 시스템 호출을 위한 인수. */
union {
int val; /* SETVAL의 값 */
struct semid_ds *buf; /* IPC_STAT & IPC_SET용 버퍼 */
ushort *array; /* GETALL & SETALL용 배열 */
struct seminfo *__buf; /* IPC_INFO용 버퍼 */
void *__pad;
};
value
SETVAL 명령을 수행할 때 사용됩니다. 세마포어를 설정할 값을 지정합니다.
buf
IPC_STAT/IPC_SET 명령에 사용됩니다. 커널에서 사용되는 내부 세마포어 데이터 구조의 복사본을 나타냅니다.
array
GETALL/SETALL 명령에 사용되는 포인터. 세트의 모든 세마포어 값을 설정하거나 검색하는 데 사용할 정수 값의 배열을 가리켜야 합니다.
나머지 인수 __buf 및 __pad 는 커널 내의 세마포어 코드에서 내부적으로 사용되며 응용 프로그램 개발자에게는 거의 또는 전혀 쓸모가 없습니다. 사실, 이 두 인수는 Linux 운영 체제에만 해당되며 다른 UNIX 구현에서는 찾을 수 없습니다.
https://12bme.tistory.com/227
https://tldp.org/LDP/lpg/node21.html
https://www.geeksforgeeks.org/ipc-full-form/
https://www.tutorialspoint.com/inter_process_communication/inter_process_communication_semaphores.htm#