Interview/OS
OS Semaphore 세마포어
김 정출
2024. 9. 28. 09:59
Semaphore 세마포어
세마포어(Semaphore)는 동기화를 위해 공유 자원에 대한 접근을 제어하는 메커니즘입니다. 여러 프로세스가 동시에 공유 메모리에 접근할 때 경쟁 조건(Race Condition)
이 발생하지 않도록 세마포어를 사용하여 동기화할 수 있습니다.
세마포어의 주요 동작:
- P 연산(Wait 또는 Down): 세마포어 값을 감소시키며, 값이 0보다 크면 자원을 사용할 수 있다는 의미입니다. 만약 값이 0이면, 자원이 해제될 때까지 대기합니다.
- V 연산(Signal 또는 Up): 세마포어 값을 증가시키며, 자원의 사용을 해제하여 다른 프로세스가 접근할 수 있게 만듭니다.
C에서는 System V 세마포어 API를 통해 세마포어를 사용할 수 있습니다.
1. 세마포어 관련 함수
1) semget(): 세마포어 집합 생성
세마포어(Semaphore)는 동기화를 위해 공유 자원에 대한 접근을 제어하는 메커니즘입니다. 여러 프로세스가 동시에 공유 메모리에 접근할 때 경쟁 조건(Race Condition)이 발생하지 않도록 세마포어를 사용하여 동기화할 수 있습니다.
세마포어의 주요 동작:
- 값이 0보다 크면 자원을 사용할 수 있다는 의미입니다. 만약 값이 0이면, 자원이 해제될 때까지 대기합니다.
- P 연산(Wait 또는 Down): 세마포어 값을 감소(-1)시키 자원의 대기를 하게함
- V 연산(Signal 또는 Up): 세마포어 값을 증가(+1)시키며 자원의 사용을 해제하여 다른 프로세스가 접근할 수 있게 만듭니다.
C에서는 System V 세마포어 API를 통해 세마포어를 사용할 수 있습니다.
1. 세마포어 관련 함수
1) semget(): 세마포어 집합 생성
세마포어 집합을 생성하거나 가져옵니다.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
key
: 세마포어를 식별하는 키.nsems
: 세마포어의 개수.semflg
: 생성 플래그 (e.g.IPC_CREAT
).
2) semop(): 세마포어 연산
세마포어의 값을 변경하는 데 사용됩니다.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semop(int semid, struct sembuf *sops, unsigned nsops);
semid
: 세마포어 식별자.sops
: 세마포어 연산을 지정하는 구조체.nsops
: 수행할 연산의 개수.
3) semctl(): 세마포어 제어
세마포어 값을 설정하거나 세마포어를 삭제합니다.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semctl(int semid, int semnum, int cmd, ...);
semid
: 세마포어 식별자.semnum
: 세마포어 집합 중 사용할 세마포어 번호.cmd
: 명령어 (e.g.SETVAL
,IPC_RMID
).
2. 세마포어와 공유 메모리 사용 예제
아래는 세마포어를 사용해 동기화된 공유 메모리 접근을 구현한 예제입니다. 하나의 프로세스가 공유 메모리에 데이터를 쓰고, 다른 프로세스가 데이터를 읽으며, 세마포어를 이용해 동시 접근을 제어합니다.
1) 프로세스 1: 공유 메모리와 세마포어를 생성하고 데이터 쓰기
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <string.h>
#include <unistd.h>
#define SHM_KEY 1234 // 공유 메모리 키
#define SEM_KEY 5678 // 세마포어 키
#define SIZE 1024 // 공유 메모리 크기
// P 연산 (세마포어 값을 감소시키고 자원이 사용 가능할 때까지 대기)
void sem_wait(int semid) {
struct sembuf p = {0, -1, SEM_UNDO}; // 첫 번째 세마포어에 대해 -1 연산
semop(semid, &p, 1);
}
// V 연산 (세마포어 값을 증가시켜 자원을 해제)
void sem_signal(int semid) {
struct sembuf v = {0, 1, SEM_UNDO}; // 첫 번째 세마포어에 대해 +1 연산
semop(semid, &v, 1);
}
int main() {
int shmid, semid;
char *shmaddr;
// 1. 공유 메모리 생성
shmid = shmget(SHM_KEY, SIZE, IPC_CREAT | 0666);
if (shmid == -1) {
perror("shmget failed");
return 1;
}
// 2. 공유 메모리 연결
shmaddr = (char *)shmat(shmid, NULL, 0);
if (shmaddr == (char *)-1) {
perror("shmat failed");
return 1;
}
// 3. 세마포어 생성
semid = semget(SEM_KEY, 1, IPC_CREAT | 0666);
if (semid == -1) {
perror("semget failed");
return 1;
}
// 4. 세마포어 초기화 (세마포어 값을 1로 설정)
semctl(semid, 0, SETVAL, 1);
// 5. 공유 메모리에 데이터 쓰기 (세마포어 동기화)
sem_wait(semid); // 자원 대기 (P 연산)
strcpy(shmaddr, "Hello from process 1 with semaphore!");
printf("Process 1 wrote to shared memory: %s\n", shmaddr);
sem_signal(semid); // 자원 해제 (V 연산)
// 6. 공유 메모리 분리
shmdt(shmaddr);
return 0;
}
2) 프로세스 2: 세마포어로 동기화된 공유 메모리 읽기
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <unistd.h>
#define SHM_KEY 1234 // 공유 메모리 키
#define SEM_KEY 5678 // 세마포어 키
#define SIZE 1024 // 공유 메모리 크기
// P 연산 (세마포어 값을 감소시키고 자원이 사용 가능할 때까지 대기)
void sem_wait(int semid) {
struct sembuf p = {0, -1, SEM_UNDO}; // 첫 번째 세마포어에 대해 -1 연산
semop(semid, &p, 1);
}
// V 연산 (세마포어 값을 증가시켜 자원을 해제)
void sem_signal(int semid) {
struct sembuf v = {0, 1, SEM_UNDO}; // 첫 번째 세마포어에 대해 +1 연산
semop(semid, &v, 1);
}
int main() {
int shmid, semid;
char *shmaddr;
// 1. 공유 메모리 가져오기
shmid = shmget(SHM_KEY, SIZE, 0666);
if (shmid == -1) {
perror("shmget failed");
return 1;
}
// 2. 공유 메모리 연결
shmaddr = (char *)shmat(shmid, NULL, 0);
if (shmaddr == (char *)-1) {
perror("shmat failed");
return 1;
}
// 3. 세마포어 가져오기
semid = semget(SEM_KEY, 1, 0666);
if (semid == -1) {
perror("semget failed");
return 1;
}
// 4. 공유 메모리에서 데이터 읽기 (세마포어 동기화)
sem_wait(semid); // 자원 대기 (P 연산)
printf("Process 2 read from shared memory: %s\n", shmaddr);
sem_signal(semid); // 자원 해제 (V 연산)
// 5. 공유 메모리 분리
shmdt(shmaddr);
// 6. 세마포어 삭제
if (semctl(semid, 0, IPC_RMID) == -1) {
perror("semctl failed");
return 1;
}
printf("Semaphore deleted successfully.\n");
return 0;
}
d