C에서 세마포어 사용
이 기사는 C에서 세마포어를 사용하는 방법에 대한 여러 가지 방법을 보여줍니다.
POSIX 세마포를 사용하여 C의 공유 변수에 대한 액세스 동기화
UNIX 기반 시스템에는 두 가지 공통 세마포어 API (POSIX 세마포어 및 System V 세마포어)가 있습니다. 후자는 POSIX API와 동일한 기능을 제공하면서 덜 단순한 인터페이스를 갖는 것으로 간주됩니다. 세마포어는 뮤텍스와 같은 또 다른 동기화 메커니즘이며 대부분 유사한 시나리오에서 활용할 수 있습니다. 세마포어는 커널에 의해 유지되는 정수이며 일반적으로0
보다 크거나 같은 초기 값으로 설정됩니다.
세마포어 객체에 대해 두 가지 작업을 수행 할 수 있습니다. 공유 리소스를 획득하고 해제하는 것에 해당하는 하나의 증가 또는 감소입니다. POSIX는 다중 스레드 워크 플로에서보다 일반적인 도구 인 명명되지 않은 세마포어에 대한 특수sem_t
유형을 제공합니다. sem_t
변수는 주어진 세마포가 프로세스 또는 프로세스의 스레드간에 공유되어야하는지 여부를 나타내는sem_init
함수로 초기화되어야합니다. 변수가 초기화되면sem_post
및sem_wait
함수를 사용하여 동기화를 구현할 수 있습니다. sem_post
는 일반적으로 공유 리소스 잠금 해제에 해당하는 세마포어를 증가시킵니다. 반대로sem_wait
는 세마포어를 감소시키고 리소스 잠금을 나타냅니다. 따라서 중요 섹션은sem_wait
로 시작하고sem_post
호출로 끝나야합니다. 하지만 성공 상태 코드를 확인하는 것은 코드를 디버깅하는 데 필수적 일 수 있습니다.
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
static long shared = 0;
static sem_t sem;
enum { THREADS = 4 };
#define errExit(msg) \
do { \
perror(msg); \
exit(EXIT_FAILURE); \
} while (0)
static void *threadFunc(void *arg) {
long loops = *((long *)arg);
for (long j = 0; j < loops; j++) {
if (sem_wait(&sem) == -1) errExit("sem_wait");
shared++;
if (sem_post(&sem) == -1) errExit("sem_post");
}
return NULL;
}
int main(int argc, char *argv[]) {
pthread_t t[THREADS];
int s;
long nloops;
if (argc != 2) {
fprintf(stderr, "Usage: %s num_loops\n", argv[0]);
exit(EXIT_FAILURE);
}
nloops = strtol(argv[1], NULL, 0);
if (sem_init(&sem, 0, 1) == -1) errExit("sem_init");
for (int i = 0; i < THREADS; ++i) {
s = pthread_create(&t[i], NULL, threadFunc, &nloops);
if (s != 0) errExit("pthread_create");
}
for (int i = 0; i < THREADS; ++i) {
s = pthread_join(t[i], NULL);
if (s != 0) errExit("pthread_join");
}
printf("shared = %ld\n", shared);
exit(EXIT_SUCCESS);
}
샘플 명령 :
./program_name 1000
출력:
shared = 4000
sem_destroy
함수를 사용하여 이름이없는 세마포 제거
sem_init
호출로 초기화 된 세마포어는sem_destroy
함수를 사용하여 제거해야합니다. sem_destroy
는 대기중인 프로세스 / 스레드가 없을 때 호출되어야합니다. sem_destroy
호출을 생략하면 일부 시스템에서 메모리 누수가 발생할 수 있습니다.
일반적으로 세마포어는 Pthread 뮤텍스에 비해 성능이 비슷하지만 일반적으로 더 나은 코드 구조를 위해 후자가 선호됩니다. 그러나 신호 처리기에서 잠금을 수정해야하는 몇 가지 시나리오가 있습니다.이 경우 함수가 비동기 적으로 안전해야하고sem_post
만 이와 같이 구현됩니다. POSIX API에는 이름이 지정된 세마포가 있는데,이를 생성하고 사용한 스레드가 종료 된 후에도 지속될 수 있습니다.
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
static long shared = 0;
static sem_t sem;
enum { THREADS = 4 };
#define errExit(msg) \
do { \
perror(msg); \
exit(EXIT_FAILURE); \
} while (0)
static void *threadFunc(void *arg) {
long loops = *((long *)arg);
for (long j = 0; j < loops; j++) {
if (sem_wait(&sem) == -1) errExit("sem_wait");
shared++;
if (sem_post(&sem) == -1) errExit("sem_post");
}
return NULL;
}
int main(int argc, char *argv[]) {
pthread_t t[THREADS];
int s;
long nloops;
if (argc != 2) {
fprintf(stderr, "Usage: %s num_loops\n", argv[0]);
exit(EXIT_FAILURE);
}
nloops = strtol(argv[1], NULL, 0);
if (sem_init(&sem, 0, 1) == -1) errExit("sem_init");
for (int i = 0; i < THREADS; ++i) {
s = pthread_create(&t[i], NULL, threadFunc, &nloops);
if (s != 0) errExit("pthread_create");
}
for (int i = 0; i < THREADS; ++i) {
s = pthread_join(t[i], NULL);
if (s != 0) errExit("pthread_join");
}
printf("shared = %ld\n", shared);
sem_destroy(&sem);
exit(EXIT_SUCCESS);
}
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn Facebook