동기화가 뭔지에 대해선 설명하지 않겠다. 리눅스에서 쓰레드 동기화를 위해 사용하는 mutex 와 semaphore 에 대해서 간략한 사용방법을 설명한다.
1. 뮤텍스(mutex)
리눅스에서 사용하는 mutex는 pthread에서 사용하는 mutex를 사용한다. 이 pthread mutex는 프로세스간 동기화에도 사용할 수는 있으나 리눅스에서는 잘 사용하지 않고 쓰레드간 동기화에 사용한다. 이 mutex 관련 함수는 다음과 같다.
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr );
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr )
mutex 를 생성하고 초기화 한다.
pthread_mutexattr_t : mutex 생성시 속성 값으로 { FAST, RECURSIVE, ERROR CHECKING } 이 있으며 보통 NULL 을 준다.
또한 pthread_mutex_init 함수를 사용하지 않고 상수들을 이용하여 정적으로 초기화 할 수 있다.
pthread_mutex_t mutex_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP ;
pthread_mutex_t mutex_lock = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
pthread_mutex_lock(pthread_mutex_t *mutex)
lock을 실행한다. 이미 다른곳에서 lock이 된 경우 , unlock 될 때까지 블록킹 된다.
pthread_mutex_trylock(pthread_mutex_t *mutex)
lock을 실행한다. 이미 다른곳에서 lock이 된경우, EBUSY를 리턴 한다.
pthread_mutex_unlock(pthread_mutex_t *mutex)
unlock을 실행한다.
pthread_mutex_destroy(pthread_mutex_t *mutex)
mutex를 삭제한다.
2. 세마포어(semaphore)
mutex와 유사하지만, mutex는 하나의 접근만 허용하지만 semaphore는 여러개의 접근도 허용하게 해준다. 또한 semaphore는 프로세스 , 쓰레드 에서 사용 될 수 있으며, SYSTEM V, POSIX 로 구분 된다.
2.1 SYSTEM V
SYSTEM V 는 전통적 semaphore 방식이다.
int semget(key_t key, int nsems, int semflag);
int semctl(int semid, int semnum, int cmd, union semun arg);
int semop(int semid, struct sembuf *sops, size_t nsops);
int semget(key_t key, int nseems, int semflag)
semaphore를 생성한다.
key_t : semaphore 식별 ID 로 IPC_PRIVATE (0 ) 또는 임의의 수, ftok() 함수에서 리턴하는 값으로 사용할수 있다.
nseems : semaphore 집합 갯수
semflag : IPC_CREATE 일 경우 key id 가 없으면 생성하도록 한다. IPC_EXCL 일 경우 key id가 존재 시 실패를 리턴한다.(이 경우 기존 미리 생성된 semaphore를 사용못한다)
semctl(int semid, int semnum, int cmd, union semun arg )
semaphore를 제어한다.
semid: semaphore 식별 ID
semnum : semaphore 집합내의 위치
cmd : 제어 명령
GETVAL : semaphore 값을 구한다.
GETPID : semaphore에 가장 최근에 접근했던 프로세서 ID 구한다.
GETNCNT : semaphore값이 증가하기를 기다리는 프로세스의 갯수
GETZCNT : semaphore값이 0이 되기를 기다리는 프로세스의 갯수
GETALL : semaphore 집합의 모든 semaphore 값을 구한다.
SETVAL : semaphore 값을 설정한다.
SETALL : semaphore 집합의 모든 semaphore 값을 설정
IPC_STAT : 정보를 구한다.
IPC_SET : semaphore 소유권과 접근허가를 설정한다.
IPC_RMID : semaphore 집합을 삭제한다.
arg: semaphore의 값을 설정하거라 값을 얻을 때 사용하는 변수
union semun{
int val;
struct semid_ds *buf;
unsigned short int *arrary;
}
semop(int semid, struct sembuf *sops, size_t nsops)
semaphore값을 변경하는 함수이다.
semid: semaphore 식별 ID
sops : semaphore 설정값 변경을 위한 값
struct sembuf {
short sem_num; semaphore 집합 번호
short sem_op; semaphore 증감값
short sem_flg; 옵션(IPC_NOWAIT : 호출 시 실행 못했을 때 실패 리턴. SEM_UNDO : 프로세서 종료시 semaphore 설정을 원래 상태로 복귀 하는 옵션. 보통 이 옵션 사용)
}
nsops : 변경하려는 갯수
2.2 POSIX semaphore
int sem_init(sem_t *sem, int pshared, unsigned int value);
int sem_wait(sem_t *sem);
int sem_trywait(sem_t* sem);
int sem_post(sem_t *sem);
int sem_getvalue(sem_t *sem, int *sval);
int sem_destroy(sem_t *sem);
sem_init(sem_t *sem, int pshared, unsigned int value)
semaphore 값을 value로 초기화 한다.
pshared : 0 이면 현 프로세스 에서 사용, 그외에는 여러 프로세스 에서 사용
sem_wait(sem_t *sem)
semaphore 값을 1 줄이고 , 0 일 경우 대기한다.
sem_trywait(sem_t *sem)
sem_wait와 동일한 기능을 하며 0일 경우 EAGAIN을 리턴한다.
sem_post(sem_t *sem)
semaphore 값을 1 증가 시킨다.
sem_getvalue(sem_t *sem, int *sval)
semaphore 값을 sval에 저장한다.
sem_destroy(sem_t *sem )
semaphore 삭제하고 해제한다.