C에서 원자 유형 사용

Jinku Hu 2023년10월12일
C에서 원자 유형 사용

이 기사에서는 C에서 원자 유형을 사용하는 방법에 대한 여러 방법을 보여줍니다.

원자 유형을 사용하여 암시 적으로 공유 리소스에 대한 액세스 동기화

원자 유형 개체는 경쟁 조건을 발생시키지 않고 동시에 여러 스레드에서 액세스하고 수정할 수있는 유일한 개체입니다. 이 기능은 다른 스레드에서 액세스되는 전역 및 정적 변수에 필수적이며 프로그램 정확성이 유지됩니다. 일반적으로 원자 유형 객체를 사용하는 것은 뮤텍스와 같은 객체 및mtx_lock,mtx_unlock등과 같은 표준 API 함수를 잠그는 대신 사용할 수 있습니다. 다음 코드 샘플은 여러 스레드가 공유 전역 카운터 변수를 증가시키는 계산 문제의 간단한 경우를 보여줍니다. 마지막으로 합계는 프로그램 끝에stdout에 인쇄됩니다. 일반적인int유형으로counter를 선언했습니다. 불행히도이 프로그램은 일부 실행이 올바른 결과를 산출하더라도 결함이 있습니다.

#include <stdio.h>
#include <stdlib.h>
#include <threads.h>
#include <unistd.h>

#ifndef NUM_THREADS
#define NUM_THREADS 4
#endif

int counter = 0;

enum { MAX_ITER = 10000 };

void incrementCounter(void *thr_id) {
  long tid;
  tid = (long)thr_id;
  printf("thread %ld started incrementing ID - %lu\n", tid, thrd_current());

  for (int i = 0; i < MAX_ITER; ++i) {
    counter += 1;
  }

  thrd_exit(EXIT_SUCCESS);
}

int main(int argc, char const *argv[]) {
  thrd_t threads[NUM_THREADS];
  int rc;
  long t;

  for (t = 0; t < NUM_THREADS; t++) {
    rc = thrd_create(&threads[t], (thrd_start_t)incrementCounter, (void *)t);
    if (rc == thrd_error) {
      printf("ERORR; thrd_create() call failed\n");
      exit(EXIT_FAILURE);
    }
  }

  for (t = 0; t < NUM_THREADS; t++) {
    thrd_join(threads[t], NULL);
  }
  printf("count = %d\n", counter);

  thrd_exit(EXIT_SUCCESS);
}

출력:

thread 0 started incrementing ID - 140097636923136
thread 2 started incrementing ID - 140097620137728
thread 1 started incrementing ID - 140097628530432
thread 3 started incrementing ID - 140097611745024
count = 18851

thrd_create호출로 다른 스레드를 생성하는 주 스레드는 카운터 변수를 증가시키지 않으므로 합계는MAX_ITER상수 및 스레드 수를 나타내는NUM_THREADS의 배수 여야합니다. 뮤텍스 잠금/잠금 해제 함수 또는 세마포어 작업으로counter += 1행을 둘러싸면이 문제를 해결할 수 있지만,이 경우atomic_int유형으로counter를 선언합니다. 이 정수 객체는 이제 원자 속성을 가지고 있다고합니다. 즉, 단일 명령으로 중단없이 액세스 할 수 있으며 프로그램의 순차적 실행을 보장합니다.

#include <stdatomic.h>
#include <stdio.h>
#include <stdlib.h>
#include <threads.h>
#include <unistd.h>

#ifndef NUM_THREADS
#define NUM_THREADS 4
#endif

atomic_int counter = 0;

enum { MAX_ITER = 10000 };

void incrementCounter(void *thr_id) {
  long tid;
  tid = (long)thr_id;
  printf("thread %ld started incrementing ID - %lu\n", tid, thrd_current());

  for (int i = 0; i < MAX_ITER; ++i) {
    counter += 1;
  }

  thrd_exit(EXIT_SUCCESS);
}

int main(int argc, char const *argv[]) {
  thrd_t threads[NUM_THREADS];
  int rc;
  long t;

  for (t = 0; t < NUM_THREADS; t++) {
    rc = thrd_create(&threads[t], (thrd_start_t)incrementCounter, (void *)t);
    if (rc == thrd_error) {
      printf("ERORR; thrd_create() call failed\n");
      exit(EXIT_FAILURE);
    }
  }

  for (t = 0; t < NUM_THREADS; t++) {
    thrd_join(threads[t], NULL);
  }
  printf("count = %d\n", counter);

  thrd_exit(EXIT_SUCCESS);
}

출력:

thread 0 started incrementing ID - 140125987915520
thread 1 started incrementing ID - 140125979522816
thread 2 started incrementing ID - 140125971130112
thread 3 started incrementing ID - 140125962737408
count = 40000
작가: 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