在 C 語言中使用 thread_local 變數

Jinku Hu 2023年10月12日
  1. 使用 _Thread_local 型別宣告帶有執行緒儲存持續時間的變數
  2. 使用 thread_local 型別宣告具有執行緒儲存持續時間的變數
在 C 語言中使用 thread_local 變數

本文將介紹幾種如何在 C 語言中使用 thread_local 變數的方法。

使用 _Thread_local 型別宣告帶有執行緒儲存持續時間的變數

C 語言為不同的儲存類別定義了多個關鍵字,例如 autostaticregisterextern。從 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

DelftStack.com 創辦人。Jinku 在機器人和汽車行業工作了8多年。他在自動測試、遠端測試及從耐久性測試中創建報告時磨練了自己的程式設計技能。他擁有電氣/ 電子工程背景,但他也擴展了自己的興趣到嵌入式電子、嵌入式程式設計以及前端和後端程式設計。

LinkedIn Facebook

相關文章 - C Thread