C에서 세마포어 사용

Jinku Hu 2023년10월12일
  1. POSIX 세마포를 사용하여 C의 공유 변수에 대한 액세스 동기화
  2. sem_destroy함수를 사용하여 이름이없는 세마포 제거
C에서 세마포어 사용

이 기사는 C에서 세마포어를 사용하는 방법에 대한 여러 가지 방법을 보여줍니다.

POSIX 세마포를 사용하여 C의 공유 변수에 대한 액세스 동기화

UNIX 기반 시스템에는 두 가지 공통 세마포어 API (POSIX 세마포어 및 System V 세마포어)가 있습니다. 후자는 POSIX API와 동일한 기능을 제공하면서 덜 단순한 인터페이스를 갖는 것으로 간주됩니다. 세마포어는 뮤텍스와 같은 또 다른 동기화 메커니즘이며 대부분 유사한 시나리오에서 활용할 수 있습니다. 세마포어는 커널에 의해 유지되는 정수이며 일반적으로0보다 크거나 같은 초기 값으로 설정됩니다.

세마포어 객체에 대해 두 가지 작업을 수행 할 수 있습니다. 공유 리소스를 획득하고 해제하는 것에 해당하는 하나의 증가 또는 감소입니다. POSIX는 다중 스레드 워크 플로에서보다 일반적인 도구 인 명명되지 않은 세마포어에 대한 특수sem_t유형을 제공합니다. sem_t변수는 주어진 세마포가 프로세스 또는 프로세스의 스레드간에 공유되어야하는지 여부를 나타내는sem_init함수로 초기화되어야합니다. 변수가 초기화되면sem_postsem_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);
}
작가: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

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