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