C11 スレッドライブラリを使用する

胡金庫 2023年10月12日
  1. C 言語で thrd_create 関数を使用して新しいスレッドを作成し指定されたルーチンを実行する
  2. C 言語で thrd_join 関数を使用して指定されたスレッドを待機する
C11 スレッドライブラリを使用する

この記事では、C 言語で C11 スレッドライブラリを使用する方法のいくつかの方法について説明します。

C 言語で thrd_create 関数を使用して新しいスレッドを作成し指定されたルーチンを実行する

スレッドのサポートは、標準の C 言語仕様では長い間延期されていましたが、ついに C11 で実現されました。それ以前は、POSIX スレッド API がマルチスレッドプログラミングを利用するための主要なツールとして使用されていました。C11 は、プラットフォームに依存せずに使用できるより標準的なインターフェースを提供したため、POSIX バージョンよりも ISO 言語 API を使用することをお勧めします。2つの API は関数プロトタイプで一致していませんが、主な機能はほとんど同じです。次の例では、4つのスレッドが開始されて printHello 関数が実行され、メインスレッドに参加せずに終了するという単純なシナリオを示しています。

thrd_create は 3つの引数を取ります。

  1. 1つ目は、スレッド識別子へのポインタです。
  2. 2 番目の引数はタイプ-thrd_start_t であり、これは関数ポインタープロトタイプの単なる typedef です。
  3. 3 番目のパラメーターは、関数に渡すことができる引数を指定します。

thrd_create のリターンステータスコードは、enum 値を使用して定義されます:thrd_successthrd_nomem および thrd_error

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

#ifndef NUM_THREADS
#define NUM_THREADS 4
#endif

void *printHello(void *thr_id) {
  long tid;
  tid = (long)thr_id;
  printf("Hello There! thread #%ld, pthread ID - %lu\n", tid, thrd_current());
  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)printHello, (void *)t);
    if (rc == thrd_error) {
      printf("ERORR; thrd_create() call failed\n");
      exit(EXIT_FAILURE);
    }
  }
  thrd_exit(EXIT_SUCCESS);
}

出力:

Hello There! thread 0, pthread ID - 140215498864384
Hello There! thread 1, pthread ID - 140215490471680
Hello There! thread 3, pthread ID - 140215473686272
Hello There! thread 2, pthread ID - 140215482078976

C 言語で thrd_join 関数を使用して指定されたスレッドを待機する

thrd_joinpthread_join 関数の類似物であり、指定されたスレッドが実行を終了するまで現在のスレッドをブロックします。スレッド識別子と、ユーザーが有効なアドレスを指定した場合にオプションでリターンステータスコードを保存できる場所を示す int ポインタの 2つの引数を取ります。すでにデタッチまたは結合されているスレッドで thrd_join が呼び出された場合、結果は未定義の動作になります。この関数は、thrd_success または thrd_error に対応する値を返します。

次のサンプルコードは、4つのスレッドが 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 = 1000 };

void *printHello(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 NULL;
}

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)printHello, (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 - 139729818216192
thread 2 started incrementing ID - 139729801430784
thread 3 started incrementing ID - 139729793038080
thread 1 started incrementing ID - 139729809823488
count = 4000
著者: 胡金庫
胡金庫 avatar 胡金庫 avatar

DelftStack.comの創設者です。Jinku はロボティクスと自動車産業で8年以上働いています。自動テスト、リモートサーバーからのデータ収集、耐久テストからのレポート作成が必要となったとき、彼はコーディングスキルを磨きました。彼は電気/電子工学のバックグラウンドを持っていますが、組み込みエレクトロニクス、組み込みプログラミング、フロントエンド/バックエンドプログラミングへの関心を広げています。

LinkedIn Facebook

関連記事 - C Thread