C에서 thread_local 변수 사용

Jinku Hu 2023년10월12일
  1. _Thread_local유형을 사용하여 스레드 저장 기간으로 변수 선언
  2. thread_local유형을 사용하여 스레드 저장 기간으로 변수 선언
C에서 thread_local 변수 사용

이 기사에서는 C에서thread_local변수를 사용하는 방법에 대한 몇 가지 방법을 설명합니다.

_Thread_local유형을 사용하여 스레드 저장 기간으로 변수 선언

C 언어는auto,static,register,extern과 같은 다른 스토리지 클래스에 대해 여러 키워드를 정의합니다. C11 표준 사양 이후_Thread_local지정자가 추가되었습니다. _Thread_local저장 기간은 스레드 생성 순간에 시작되어 종료로 끝납니다. _Thread_local객체에 저장된 값은 스레드가 시작될 때 초기화되고 스레드가 종료되면 정리됩니다. 일반적으로 스레드 로컬 개체는 공유 리소스의 경쟁 조건을 피하기위한 또 다른 대안입니다. 즉,_Thread_local자격을 갖춘 객체가 각 스레드에 대해 별도의 인스턴스를 가지므로 스레드간에 데이터를 암시 적으로 분리합니다.

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

#ifndef NUM_THREADS
#define NUM_THREADS 4
#endif

_Thread_local 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;
  }

  return (void *)counter;
}

int main(int argc, char const *argv[]) {
  thrd_t threads[NUM_THREADS];
  int rc, sum = 0;

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

  int retval;
  for (int i = 0; i < NUM_THREADS; ++i) {
    thrd_join(threads[i], &retval);
    sum += retval;
  }
  printf("count = %d\n", sum);

  thrd_exit(EXIT_SUCCESS);
}

출력:

thread 1 started incrementing ID - 140162648991488
thread 0 started incrementing ID - 140162657384192
thread 2 started incrementing ID - 140162640598784
thread 3 started incrementing ID - 140162632206080
count = 40000

thread_local유형을 사용하여 스레드 저장 기간으로 변수 선언

또는 C 언어는 지정자를_Thread_local로 표시하기 위해 매크로 표현식thread_local을 정의합니다. thread_local변수는 모든 스레드가 볼 수 있도록 파일 범위에서 선언되어야합니다. 그렇지 않으면 사용자가static지정자를 명시 적으로 추가하여 범위를 파일 레벨로 확장 할 수도 있습니다. 스레드가thread_local오브젝트의 값을 메인 스레드에 전달해야하므로 프로그램 구조를 수정해야합니다. 단순 카운터 프로그램을 구현하는 이전 예제 코드는 증가 된 카운터 값을 호출 스레드로 다시 전달하도록 수정해야합니다. 따라서thrd_join함수와 스레드 루틴의 반환 값을 저장하는 두 번째 인수를 사용해야합니다. 증가 된 모든 값은 메인 스레드에서 합산되어야하며, 이는 최종 결과를stdout에 인쇄하는 역할도 담당합니다.

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

#ifndef NUM_THREADS
#define NUM_THREADS 4
#endif

thread_local 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;
  }

  return (void *)counter;
}

int main(int argc, char const *argv[]) {
  thrd_t threads[NUM_THREADS];
  int rc, sum = 0;

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

  int retval;
  for (int i = 0; i < NUM_THREADS; ++i) {
    thrd_join(threads[i], &retval);
    sum += retval;
  }
  printf("count = %d\n", sum);

  thrd_exit(EXIT_SUCCESS);
}

출력:

thread 1 started incrementing ID - 140162648991488
thread 2 started incrementing ID - 140162640598784
thread 0 started incrementing ID - 140162657384192
thread 3 started incrementing ID - 140162632206080
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

관련 문장 - C Thread