C 言語でミューテックスロックを使用する

胡金庫 2023年10月12日
C 言語でミューテックスロックを使用する

この記事では、C 言語でミューテックスロックを利用する方法をいくつか説明します。

pthread_mutex_tpthread_mutex_lock 関数を使ってコードの重要な部分をガードする

スレッドはアドレス空間を共有しているため、グローバル変数のような共有データの変更は同期化されていなければなりません。以下のコードでは、pthread_create 呼び出しで 4つの追加スレッドを作成し、func3 を実行の開始点として渡していることに注意してください。func3 はグローバル変数 shared を 1つずつ変更し、10000 回の for ループを繰り返します。したがって、4つのスレッドが shared の値を 10000 ずつインクリメントすると、プログラムは 40000 を出力するはずです。

以下のコードを実行すると、結果は何らかの乱数の整数になりますが、40000 は出力されません。この挙動は一般的に競合状態に分類され、与えられたスレッドが互いに相談せずに共有変数にアクセスしていることを暗示しています。す。つまり、ループの実行がインターリーブすると、共有変数へのアクセスとストアが不整合になり、最終的に不正確な合計が生成されます。

複数のスレッドがメモリ上の同じオブジェクトを変更するコード部分はクリティカルセクションと呼ばれます。一般的に、クリティカルセクションは、現在のスレッドが実行を終了するまで他のスレッドを強制的に待たせ、すべてのスレッドが正しいインクリメント値を取得することを保証する何らかのタイプのロックで保護されている必要があります。Mutex は、func3for ループのようにクリティカルセクションを保護するために利用できるロックタイプの一つです。

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

#ifndef NUM_THREADS
#define NUM_THREADS 4
#endif

int shared = 0;

void* func3(void* param) {
  printf("Incrementing the shared variable...\n");
  for (int i = 0; i < 10000; ++i) {
    shared += 1;
  }
  return 0;
}

int main() {
  pthread_t threads[NUM_THREADS];

  for (int i = 0; i < NUM_THREADS; ++i) {
    pthread_create(&threads[i], NULL, func3, NULL);
  }

  for (int i = 0; i < NUM_THREADS; ++i) {
    pthread_join(threads[i], NULL);
  }

  printf("%d\n", shared);
  exit(EXIT_SUCCESS);
}

出力:

Incrementing the shared variable...
Incrementing the shared variable...
Incrementing the shared variable...
Incrementing the shared variable...
30384

今回は POSIX スレッドライブラリとその組み込みの pthread_mutex_t 型を利用します。pthread_mutex_t 型変数は通常、static 格納期間として宣言されています。ミューテックスは使用する前に一度だけ初期化する必要がある。mutex が static と宣言されている場合、PTHREAD_MUTEX_INITIALIZER マクロを用いて初期化する必要があります。mutex が初期化されると、スレッドは pthread_mutex_lockpthread_mutex_unlock 関数を利用することができます。pthread_mutex_lock は引数として渡された mutex オブジェクトをロックします。既にミューテックスがロックされていた場合は、ミューテックスが利用可能になるまで呼び出したスレッドはブロックされます。mutex のロックを解除するには pthread_mutex_unlock を呼び出す必要があります。同じミューテックスを待っているスレッドがある場合、スケジューリングポリシーによってどちらのスレッドがオブジェクトロックを受けるかが決まります。最後に、4つのスレッドのそれぞれに対して pthread_join を呼び出して shared という整数を出力します。

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

#ifndef NUM_THREADS
#define NUM_THREADS 4
#endif

int shared = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void* func3(void* param) {
  pthread_mutex_lock(&mutex);
  printf("Incrementing the shared variable...\n");
  for (int i = 0; i < 10000; ++i) {
    shared += 1;
  }
  pthread_mutex_unlock(&mutex);
  return 0;
}

int main() {
  pthread_t threads[NUM_THREADS];

  for (int i = 0; i < NUM_THREADS; ++i) {
    pthread_create(&threads[i], NULL, func3, NULL);
  }

  for (int i = 0; i < NUM_THREADS; ++i) {
    pthread_join(threads[i], NULL);
  }

  printf("%d\n", shared);
  exit(EXIT_SUCCESS);
}

出力:

Incrementing the shared variable...
Incrementing the shared variable...
Incrementing the shared variable...
Incrementing the shared variable...
40000
著者: 胡金庫
胡金庫 avatar 胡金庫 avatar

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

LinkedIn Facebook