세마포어는 Edsger Wybe Dikstra가 고안한 두 개의 원자적 함수(=한 번 실행되면 중간에 멈출 수 없는 함수)로 조작되는 두 정적 변수를 의미한다. 공유 자원에 대한 접근을 제한하는 방법으로 사용된다.
식사하는 철학자들 문제(The Dining-Philosophers Problem) : 동시성과 교착 상태를 설명하는 문제

주어진 상황과 같이 5 명의 철학자들 앞에는 5 개의 스파게티가 있고, 스파게티 사이마다 포크가 있다. 철학자들은 서로 대화할 수 없다. 철학자가 스파게티를 먹기 위해서는 양 옆의 포크를 동시에 들어야 한다. 만약 모든 철학자들이 왼쪽 포크를 들고 오른 쪽 포크를 든다면, 모든 철학자들이 오른 쪽 포크를 들 수 없어서 스파게티를 먹지 못하는 교착 상태에 빠질 수 있다. 이러한 문제를 식사하는 철학자들 문제라 한다.
해결 방법 : 세마포어 변수, P(감소), V(증가) 연산을 이용하여 동기화 한다.
P(sem) :
if(sem > 0){
sem--;
}
else{
wait until sem > 0;
sem--;
}
V(sem) :
sem++;
wakeup waiting process
리눅스는 세마포어 기능을 <sys/sem.h>를 이용하여 제공한다.
semget() : 세마포어 생성
semop() : 세마포어 연산(p, v)
semctl() : 세마포어 제어 및 삭제
다음은 세마포어를 이용하여 공유 자원을 관리하는 예제이다. cnt는 전체 자원의 개수가 된다.
#include <stdio.h>
#include <unistd.h>
#include <sys/sem.h>
int cnt = 0;
static int semid;
void p() /* 세마포어의 P 연산 */
{
struct sembuf pbuf;
pbuf.sem_num = 0; //배열에서의 세마포어의 인덱스, 세마포어가 여러 개일 수 있다.
pbuf.sem_op = -1; //세마포어 동작
pbuf.sem_flg = SEM_UNDO; //동작을 위한 플래그
if (semop(semid, &pbuf, 1) == -1) /* 세마포어의 감소 연산을 수행한다. */
perror("p : semop()");
}
void v() /* 세마포어의 V 연산 */
{
struct sembuf vbuf;
vbuf.sem_num = 0;
vbuf.sem_op = 1;
vbuf.sem_flg = SEM_UNDO;
if (semop(semid, &vbuf, 1) == -1) /* 세마포어의 증가 연산을 수행한다. */
perror("v : semop()");
}
int main()
{
union semun
{
int val;
struct semid_ds *buf;
unsigned short int *array;
} arg;
/* 세마포어에 대한 채널 얻기 */
if ((semid = semget(IPC_PRIVATE, 1, IPC_CREAT | 0666)) == -1)
{
perror("semget()");
return -1;
}
arg.val = 1; /* 세마포어 값을 1로 설정 */
if (semctl(semid, 0, SETVAL, arg) == -1)
{
perror("semctl() : SETVAL");
return -1;
}
while (1)
{
if (cnt >= 8)
{
cnt--;
p();
printf("decrease : %d\n", cnt);
break;
}
else
{
cnt++;
v();
printf("increase : %d\n", cnt);
usleep(100);
}
}
/* 세마포어에 대한 채널 삭제 */
if (semctl(semid, 0, IPC_RMID, arg) == -1)
{
perror("semctl() : IPC_RMID");
return -1;
}
return 0;
}
코드 출처 : https://github.com/valentis/LinuxProgrammingWithRaspberryPi
GitHub - valentis/LinuxProgrammingWithRaspberryPi: Linux Programming With Raspberry Pi
Linux Programming With Raspberry Pi. Contribute to valentis/LinuxProgrammingWithRaspberryPi development by creating an account on GitHub.
github.com
'컴퓨터 과학 > 리눅스 프로그래밍' 카테고리의 다른 글
[이론]리눅스 드라이버 원리 (1) | 2025.05.19 |
---|---|
[이론]리눅스 프로그래밍 - 네트워크(TCP/IP, UDP) (2) | 2025.05.09 |
[이론] 스레드(Thread)와 뮤텍스 스레드(Mutex Thread) (0) | 2025.05.08 |
[이론]리눅스 프로그래밍 - 프로세스와 쓰레드 (1) | 2025.05.08 |
[이론] 리눅스 프로그래밍 - 입출력 함수 (0) | 2025.05.06 |