세마포어의 기본 동작 구조
- 세마포어는 중요한 처리 부분에 들어가기 전에
**p()**
함수를 실행해 잠금 기능을 수행
- 처리를 마치면
v()
함수를 실행해 잠금을 해체
- 잠금 기능을 수행 중인 동안에는 다른 프로세스가 처리 부분의 코드를 실행할 수 없다.
- sem은 세마포어 값을 의미
p(sem);
v(sem);
p()
p(sem){
while sem == 0 do wait;
sem--;
}
- sem이 0이면 다른 프로세스가 처리 부분을 수행하고 있다는 의미.
v()
v(sem){
sem++;
if(대기 중 프로세스가 있으면)
대기 중인 첫 번째 프로세스 동작
}
세마포어 생성 : semget()
- key : IPC_PRIVATE 또는 ftok() 함수로 생성한 키를 지정
- nsems 에는 생성할 세마포어 개수를 지정
- 세마포어는 집합 단위로 처리되므로 한 식별자에 여러 세마포어가 새애성.
- 플래그는 IPC_CREAT, IPC_EXCL을 사용
세마포어 정보를 담고 있는 구조체는 shmid_ds
- sem_perm : IPC 공통 구조체
- sem_otime : 세마포어 연산을 수행한 마지막 시간
- sem_ctime : 세마포어 접근권한 변경 마지막 시간
- sem_nsems : 세마포어 집합의 세마포어 개수
- 새로운 세마포어 식별자를 리턴할 때 구조체의 설정
- sem_perm.cuid, sem_perm.uid : 함수를 호출한 프로세스의 유효 사용자 ID로 설정
- sem_perm.cgid, sem_perm.gid : 함수를 호출한 프로세스의 유효 그룹 ID로 설정
- sem_perm.mode : semflg 값으로 설정
- sem_nsems : nsems 값으로 설정, 세마포어 집합이 생성되지 않으면 0으로 설정될 수도 있음
- sem_otime : 0으로 설정
- sem_ctime : 현재 시각으로 설정
- 세마포어에 연관된 값
- semval : 세마포어의 값
- sempid : 세마포어에 최근 접근했던 프로세스의 프로세스 식별번호
- semncnt : 세마포어의 값이 현재보다 더 큰 값을 갖기를 기다리는 프로세스의 수
- semzcnt : 세마포어의 값이 0이 되기를 기다리는 프로세스의 수
세마포어 제어 : semctl()
- 세 번째 인자인 cmd
- IPC_STAT : 현재 세마포어 정보를 arg.buf로 지정한 메모리에 저장
- iPC_SET : 지정한 값으로 변경
- IPC_RMID : semid로 지정한 세마포어 관련 구조체를 제거
- IPC_INFO
- 구조체 항
- GETALL : 세마포어 집합에 있는 모든 세마포어의 semval 값을 arg.array가 가리키는 배열에 저장
- GETNCNT : 세마포어의 semncnt 값을 읽어옴
- GETVAL : 세마포어의 semval 값을 읽어옴
- SETVAL : 세마포어의 semval 값을 arg.val로 설정
- GETPID : 세마포어의 sempid 값을 읽어옴
- GETZCNT : 세마포어의 semzcnt 값을 읽어옴
- SETALL : 세마포어 집합에 있는 모든 세마포어의 semval 값을 arg.array가 가리키는 배열값으로 설정
세마포어 연산 : semop()
semid가 가리키는 세마포어에 크기가 nsops인 sembuf 구조체로 지정한 연산을 실행.
- sem_flg ; IPC_NOWAIT나 SEM_UNDO를 지정
- SEM_UNDO : 프로세스가 비정상적으로 갑자기 종료될 때 세마포어 동작 취소.
sem_op < 0 일 때
세마포어 잠금 기능을 수행. 공유 자원 사용 목적
- semval ≥ |sem_op| → semval -= |sem_op|
- semval < sem_op && semflg == IPC_NOWAIT → return
- semval < && semflg ≠ IPC_NOWAIT → semnncnt++
- 시스템에서 semid가 제거, 이 경우 errno가 EIDRM
sem_op > 0 일 때
세마포어 잠금 해제, 사용 중이던 공유 자원 돌려줌
sem_op 값이 semval 값에 더해짐.
sem_op == 0 일 때
- semval 값이 0이면 semop() 함수는 즉시 리턴
- semval 값이 0이 아니고 sem_flg에 IPC_NOWAIT이 설정되어 있으면 semop() 함수는 즉시 리턴
- semval 값이 0이 아니고 sem_flg에 IPC_NOWAIT이 설정되어 있지 않으면 semop() 함수는 semzcnt 값을 증가시키고 semval 값이 0이 되기를 기다림
semval = 세마포어 현재 값
sem_op = 세마포어 연산 1, 0, -1 ?
세마포어 생성과 초기화
void initsem(key_t semkey)
union semun{
int val;
struct shmid_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, semunargs);
}
return semid;
}
세마포어 연산
void semlock(int semid)
int semlock(int semid){
struct sembuf buf;
buf.sem_num = 0;
buf.sem_op = -1;
buf.sem_flg = SEM_UNDO;
return 0;
}
void semunlock(int semid)
int semunlock(int semid){
struct sembuf buf;
buf.sem_num = 0;
buf.sem_op = 1;
buf.sem_op = SEM_UNDO;
return 0;
}
void semhandle()
void semhandle(){
int semid;
pid_t pid = getpid();
if((semid = initsem(1)) < 0) exit(1);
semlock(semid);
semunlock(semid);
exit(0);
}
int main(){
int a;
for(a = 0 ; a < 3; a++)
if(fork() == 0)) semhandle();
}