세마포어
세마포어
- 프로세스 간 통신을 위한 메커니즘
- 다른 메커니즘과 다르게 프로세스 간 데이터를 동기화하고 보호하는 데에 목적이 있음
- 메시지 큐, 공유 메모리 등의 메커니즘은 프로세스 간 데이터 전송을 목적으로 함
- 공유 메모리를 통해서 프로세스 간 통신을 하는 등의 공유된 자원에 여러 개의 프로세스가 동시에 접근을 하면, 데이터가 손상될 수 있음
- 여러 개의 프로세스에 의해 공유되는 자원의 접근 제어를 위한 도구임
- 커널에서 전역적으로 관리함
- 경쟁 상태
- 여러 개의 프로세스가 공유된 자원에 동시에 접근하는 경우에 데이터를 사용하기 위해 경쟁하는 현상
- 임계영역
- 여러 개의 프로세스에 의해 접근되는 공유 영역
- 손상되지 않게 보호되어야 하는 자원가 연산을 포함한 영역
- 동기화
- 경쟁 상태를 해결하기 위해 프로세스의 동작을 제어하는 프로토콜
세마포어의 작동 원리
- 세마포어는 상호 배제 알고리즘으로 임계영역의 자원을 보호함
- 차단을 원하는 자원에 대해서 세마포어를 생성하면, 해당 자원을 가리키는 세마포어가 할당됨
- 세마포어 값을 검사하여, 자원에 접근할 수 있는지 여부를 결정함
- 세마포어 값이 0인 경우에, 임계영역의 자원에 접근할 수 없음
- 세마포어 값이 0 보다 큰 정수인 경우에, 해당 정수의 크기만큼 프로세스가 접근할 수 있음
- 세마포어의 값이 1인경우로 예를 들어봄
- 프로세스가 임계영역의 자원에 접근하면, 세마 포어의 값을1 감소시켜 다른 프로세스의 접근을 방지함
- 자원 사용을 종료하면 세마포어 값을 1 증가시켜 다른 프로세스의 접근을 허가함
- IPC키 회득
- 세마포어 생성
- 임계영역 잠금
- 공유자원사용
- 임계영역 해제
- 세마포어 제거
세마포어 함수
ftok()
semget()
#include <sys/sem.h>
#include <sys/types.h>
int semget(key_t key, int nsems, int semflags);
- 설명
- 세마포어 또는 세마포어 집합을 생성하고 접근할 수 있는 식별자를 반환함
- 인자
- key : 세마포어 또는 세마포어 집합을 식별하는 키값
- nsems : 생성하고자 하는 세마포어의 개수
- 최초로 세마포어를 생성하는 생성자의 경우에는 보통 1을 사용함
- 그 외의 세마포어를 사용하는 소비자의 경우에 0을 사용함
- semflags : 세마포어의 생성에 관한 플래그
- 반환
- 성공하면, 세마포어 식별자 또는 세마포어 집합 식별자
- 실패하면 -1
struct sembuf
#include <sys/sem.h>
#include <sys/types.h>
struct sembuf
{
short sem_num; // 세마포어 집합의 인덱스 사이즈
short sem_op; // 세마포어 연산
short sem_flg; // 연산 옵션
};
- sem_num
- 세마포어 집합의 인덱스 사이즈
- 보통 하나의 세마포어를 지정해서 사용하므로 0을 사용함
- sem_op
- 세마포어 연산 동작
- 양의 정수인 경우에 세마포어 값을 해당 정수만큼 증가시킴 (다른 프로세스의 접근을 허용함)
- 보통 1을 사용
- 음의 정수인 경우에 세마포어 값을 해당 정수의 절대값만큼 감소 시킴
- 보통 -1을 사용
- sem_flg
- 세마포어 연산 동작에 관한 플래그
- IPC_NOWAIT
- 임계영역에 접근 할 수 없는 경우에 대기하지 않음
- SEM_UNDO
- 프로세스가 세마포어를 반환하지 않고 종료하는 경우에 커널에서 스스로 세마포어 값을 증가 시킴
semop()
#include <sys/sem.h>
#include <sys/types.h>
int semop(int semid, struct sembuf * buf, unsigned int nsops);
- 설명
- 세마포어 또는 세마포어 집합의 값을 변경함
- 인자
- semid : 세마포어의 식별자
- buf : 세마포어 연산을 저장한 메모리 영역의 주소
- nsops : 변경하고자 하는 세마포어의 개수
- 반환
- 성공하면 0
- 실패하면 -1
struct semid_ds
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
struct semid_ds
{
struct ipc_perm sem_perm; // 퍼미션
struct sem *sem_base; // 집합의 첫번째 세마포어를 가리키는 포인터
time_t sem_otime; // 마지막 연산 시간
time_t sem_ctime; // 마지막 변경 시간
unsigned short sem_nsems; // 세마포어 개수
};
union semun
- 사용자 정의 공용체
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
union semun
{
int val;
struct semid_ds *buf;
unsigned short int *array;
};
semctl()
#include <sys/sem.h>
int semctl(int semid, int semnum, int cmd, union semun buf);
- 설명
- 세마포어 또는 세마포어 집합을 제어함
- 인자
- semid : 세마포어의 식별자
- semnum : 세마포어 집합에서 해당 세마포어의 인덱스
- cmd : 제어 동작에 관한 플래그
- GETVAL : 세마포어를 값을 지정한 메모리 공간에 저장함.
- GETPID : 세마포어를 가장 최근에 사용한 프로세스의 PID를 지정한 메모리 공간에 저장함
- GETNCNT : 세마포어 값이 증가하기를 기다리는 프로세스의 개수를 지정한 메모리 공간에 저장함
- GETZCNT : 세마포어 값이 0이 되기를 기다리는 프로세스의 개수를 지정한 메모리 공간에 저장함
- GETALL : 세마포어 집합의 모든 세마포어 값을 지정한 메모리 공간에 저장함
- SETVAL : 세마포어 값을 설정함
- SETALL : 세마포어 집합의 모든 세마포어 값을 설정함
- IPC_RMID : 지정한 세마포어를 제거함
- IPC_SET : 세마포어의 정보를 지정한 정보로 변경함
- IPC_STAT : 세마포어의 정보를 지정한 메모리 공간에 저장함
- buf : 제어에 사용되는 공용체
- 반환
- 성공하면 0
- 실패하면 -1
- 예시
- shm 헤더 (MyShm.h)
#ifndef __MYSHM_H__
#define __MYSHM_H__
#define SHM_MAX_SIZE 512
#define SHM_PERMS 0600
#define MY_SHM_KEY 1234
int creatShm(int key);
int openShm(int key);
int closeShm(int shmid);
#endif // !__MYSHM_H__AKG
#include "MyShm.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
int creatShm(int key){
int shmid = shmget((key_t)key, SHM_MAX_SIZE,
IPC_CREAT|IPC_EXCL|SHM_PERMS);
if(shmid == -1){
perror("createShm() error");
exit(0);
}
return shmid;
}
int openShm(int key){
int shmid = shmget((key_t)key,SHM_MAX_SIZE,IPC_CREAT);
return shmid;
}
int closeShm(int shmid){
return shmctl(shmid, IPC_RMID,0);
}
- sem 헤더 (MySem.h)
#ifndef __MYSEM_H__
#define __MYSEM_H__
#define SEM_MAX_NUM 1
#define SEM_ERMS 0600
#define MY_SEM_SERV_KEY 1357
#define MY_SEM_CLNT_KEY 2468
union semun
{
int val;
struct semid_ds *buf;
unsigned short int *array;
};
int creatSem(int key);
int openSem(int key);
int lockSem(int semid);
int unlockSem(int semid);
int closeSem(int semid);
#endif // !__MYSEM_H__
#include "MySem.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
int creatSem(int key){
int semid = semget((key_t)key, SEM_MAX_NUM,IPC_CREAT|SEM_ERMS);
if(semid == -1){
perror("creatSem() error");
exit(0);
}
return semid;
}
int openSem(int key){
int semid = semget((key_t)key, SEM_MAX_NUM, IPC_CREAT);
return semid;
}
int lockSem(int semid){
struct sembuf buf = {0,-1,SEM_UNDO};
return semop(semid , &buf, SEM_MAX_NUM);
}
int unlockSem(int semid){
struct sembuf buf = {0,1,SEM_UNDO};
return semop(semid, &buf, SEM_MAX_NUM);
}
int closeSem(int semid){
return semctl(semid, 0,IPC_RMID,0);
}
- 서버
#include "MyShm.h"
#include "MySem.h"
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/types.h>
void signalHandler(int signum);
int shmid =0;
int *shmaddr = NULL;
int semidServ = 0;
int semidClnt =0;
int main(int argc, char const *argv[]){
int req =0;
int res =0;
union semun semunBuf;
shmid = creatShm(MY_SHM_KEY);
shmaddr = shmat(shmid, NULL,0);
semidServ = creatSem(MY_SEM_SERV_KEY);
semunBuf.val = 0;
semctl(semidServ, 0, SETVAL,semunBuf);
semidClnt = creatSem(MY_SEM_CLNT_KEY);
semunBuf.val = 1;
semctl(semidClnt,0,SETVAL, semunBuf);
signal(SIGINT, signalHandler);
while(1){
puts("wait ....");
lockSem(semidServ);
memcpy(&req, shmaddr,sizeof(int));
res = req + 1;
memcpy(shmaddr, &res,sizeof(int));
unlockSem(semidClnt);
printf("Request : %d\\n",req);
printf("Response : %d\\n",res);
fflush(stdout);
}
return 0;
}
void signalHandler(int signum){
if (signum ==SIGINT){
closeSem(semidClnt);
closeSem(semidServ);
shmdt(shmaddr);
closeShm(shmid);
exit(0);
}
}
- 클라이언트
#include "MySem.h"
#include "MyShm.h"
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/types.h>
void signalHandler(int signum);
int shmid =0;
int *shmaddr = NULL;
int semidServ = 0;
int semidClnt =0;
int main(int argc, char const*argv[]){
int req =0;
int res =0;
shmid = openShm(MY_SHM_KEY);
shmaddr = shmat(shmid,NULL,0);
semidServ = openSem(MY_SEM_SERV_KEY);
semidClnt = openSem(MY_SEM_CLNT_KEY);
signal(SIGINT, signalHandler);
while(1){
printf("<< ");
scanf("%d", &req);
fflush(stdout);
fflush(stdin);
lockSem(semidClnt);
memcpy(shmaddr, &req, sizeof(int));
unlockSem(semidServ);
lockSem(semidClnt);
memcpy(&res,shmaddr, sizeof(int));
unlockSem(semidClnt);
printf(">> %d\\n",res);
}
return 0;
}
void signalHandler(int signum){
if (signum == SIGINT){
shmdt(shmaddr);
exit(0);
}
}
'시스템 소프트웨어' 카테고리의 다른 글
공유 메모리 (Shared Memory) (0) | 2023.03.11 |
---|---|
메세지 큐 (Massage Queue) (0) | 2023.03.09 |
파이프 (Pipe) (0) | 2023.03.09 |
연결 리스트 (Linked list) (0) | 2023.03.08 |
배열과 문자열 (Array and String) (0) | 2023.03.07 |