Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 15140] ファイルの概要

このコミットは、Go言語のランタイムにおけるデータ競合検出器(race detector)のテストデータとして使用されるCGO(CとGoの相互運用)ファイル src/pkg/runtime/race/testdata/cgo_test_main.go から、pthread.h ヘッダーのインクルードとその関連するPOSIXスレッド同期プリミティブ(ミューテックスと条件変数)の使用を削除するものです。代わりに、GCCの組み込みアトミック関数 __sync_fetch_and_add を用いたよりシンプルな同期メカニズムに置き換えられています。

コミット

commit 6b1b613d6aa77da31348bfe76991e564c106bbba
Author: Dmitriy Vyukov <dvyukov@google.com>
Date:   Tue Feb 5 13:08:07 2013 +0400

    runtime/race: do not include pthread.h
    Fixes #4721.
    
    R=alex.brainman, minux.ma
    CC=golang-dev
    https://golang.org/cl/7275048

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/6b1b613d6aa77da31348bfe76991e564c106bbba

元コミット内容

このコミットの目的は、「runtime/race: pthread.h をインクルードしない」ことです。これは、Goランタイムのデータ競合検出器のテストコードにおいて、pthread.h への依存を取り除くことを意味します。コミットメッセージには Fixes #4721. と記載されており、これは当時のGoの課題追跡システムにおける特定の課題を解決するものであることを示唆しています。

変更の背景

Go言語のランタイムにおけるデータ競合検出器は、並行処理における潜在的なデータ競合を特定するための重要なツールです。この検出器のテストは、様々な並行処理シナリオをシミュレートするためにCGOを利用することがあります。

以前の cgo_test_main.go ファイルでは、C言語部分の同期に pthread ライブラリのミューテックスと条件変数が使用されていました。しかし、pthread はPOSIXシステムに特化したものであり、テストの移植性やビルド環境の複雑さを増す可能性があります。

この変更の背景には、以下の理由が考えられます。

  1. 依存関係の削減: テストコードから不必要な外部ライブラリ(pthread)への依存を取り除くことで、ビルドプロセスを簡素化し、テストのセットアップを容易にします。
  2. 移植性の向上: pthread はPOSIXシステムに限定されるため、Windowsなどの非POSIX環境でのテスト実行に課題が生じる可能性があります。GCCの組み込みアトミック関数は、より広範なプラットフォームで利用可能であり、テストの移植性を高めます。
  3. テストの簡素化: テストの目的が特定の同期メカニズムの正確な動作を検証することではなく、データ競合検出器の機能検証である場合、よりシンプルで軽量な同期プリミティブで十分です。ビジーループとアトミック操作は、テストの目的を達成しつつ、コードを簡潔に保つことができます。
  4. 課題 #4721 の解決: コミットメッセージにある Fixes #4721. は、当時のGoの課題追跡システム(おそらくGoogle Code)で報告されていた特定の課題を解決するための変更であることを示しています。この課題は、pthread.h の使用に関連する問題(例えば、特定の環境でのコンパイルエラーやリンケージの問題)であった可能性が高いです。

前提知識の解説

このコミットを理解するためには、以下の技術的な概念について基本的な知識が必要です。

  1. Go言語のCGO: Go言語がC言語のコードを呼び出し、C言語のコードがGo言語のコードを呼び出すためのメカニズムです。import "C" を使用してCコードをGoプログラムに組み込むことができます。
  2. データ競合(Data Race): 複数のゴルーチン(またはスレッド)が同時に同じメモリ位置にアクセスし、少なくとも1つのアクセスが書き込みであり、かつそれらのアクセスが同期メカニズムによって保護されていない場合に発生するバグです。データ競合は予測不能な動作を引き起こす可能性があります。
  3. Goランタイムのデータ競合検出器(Race Detector): Go言語に組み込まれているツールで、プログラム実行中にデータ競合を検出し、報告します。go run -racego build -race などで有効にできます。
  4. POSIXスレッド(pthread): POSIX(Portable Operating System Interface)標準で定義されたスレッドAPIです。マルチスレッドプログラミングにおいて、スレッドの生成、同期(ミューテックス、条件変数など)、管理を行うための標準的なインターフェースを提供します。
    • pthread_mutex_t: スレッド間で共有されるリソースへのアクセスを排他的に制御するためのミューテックス(相互排他ロック)です。
    • pthread_cond_t: スレッドが特定の条件が満たされるまで待機し、他のスレッドがその条件を通知するために使用する条件変数です。
    • pthread_mutex_lock() / pthread_mutex_unlock(): ミューテックスをロック/アンロックする関数です。
    • pthread_cond_wait(): 条件変数が通知されるまでミューテックスを解放し、スレッドを待機させる関数です。
    • pthread_cond_broadcast(): 待機しているすべてのスレッドに条件が満たされたことを通知する関数です。
  5. アトミック操作(Atomic Operations): 複数のスレッドから同時にアクセスされても、その操作全体が不可分(アトミック)に実行されることを保証する操作です。これにより、データ競合を防ぎます。
    • __sync_fetch_and_add: GCC(GNU Compiler Collection)が提供する組み込みアトミック関数の一つです。これは、指定されたメモリ位置の値を読み取り、それに値を加算し、その結果をメモリ位置に書き込み、元の値を返します。この操作はアトミックに実行されます。

技術的詳細

このコミットの技術的な核心は、CGOコードにおける同期メカニズムの変更です。

変更前は、C言語部分で pthread ライブラリを使用して sync 変数のアクセスを同期していました。

  • Notify 関数では、pthread_mutex_lock でミューテックスをロックし、sync = 1 で変数を設定した後、pthread_cond_broadcast で条件変数をブロードキャストし、pthread_mutex_unlock でミューテックスをアンロックしていました。これは、sync 変数の変更を他の待機スレッドに安全に通知するための典型的なパターンです。
  • Wait 関数では、pthread_mutex_lock でミューテックスをロックし、while(sync == 0) pthread_cond_wait(&cv, &mtx);sync が0の間、条件変数を待機していました。条件変数の待機中はミューテックスが解放され、通知されると再度ミューテックスが取得されます。その後、pthread_mutex_unlock でミューテックスをアンロックしていました。

変更後は、pthread.h のインクルードと pthread 関連のコードが完全に削除されました。

  • Notify 関数は、__sync_fetch_and_add(&sync, 1); という単一のアトミック操作に置き換えられました。これは sync 変数の値をアトミックに1増加させることを意味します。このテストの文脈では、sync が0から非0に変化すれば十分であるため、具体的な値は重要ではありません。
  • Wait 関数は、while(__sync_fetch_and_add(&sync, 0) == 0) {} というビジーループに置き換えられました。__sync_fetch_and_add(&sync, 0)sync の値を変更せずに読み取るアトミック操作です。つまり、sync の値が0でなくなるまで、CPUサイクルを消費しながらループし続けます。これは、テストコードのような短期間の待機には許容される場合がありますが、一般的なプロダクションコードではCPUリソースを無駄にするため、推奨されません。

この変更により、テストコードは pthread ライブラリへの依存をなくし、より軽量でプラットフォームに依存しないGCC組み込みアトミック関数を使用するようになりました。これは、特にデータ競合検出器のテストという文脈において、同期のオーバーヘッドを減らし、テストの実行を簡素化する効果があります。

コアとなるコードの変更箇所

変更されたファイルは src/pkg/runtime/race/testdata/cgo_test_main.go のみです。

--- a/src/pkg/runtime/race/testdata/cgo_test_main.go
+++ b/src/pkg/runtime/race/testdata/cgo_test_main.go
@@ -5,26 +5,16 @@
 package main
 
 /*
-#include <pthread.h>
-#
-#pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
-#pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
+int sync;
+
+void Notify(void)
+{
+	__sync_fetch_and_add(&sync, 1);
+}
+
+void Wait(void)
+{
+	while(__sync_fetch_and_add(&sync, 0) == 0) {}
+}
 int sync;
-
-void Notify(void)
-{
-	pthread_mutex_lock(&mtx);
-	sync = 1;
-	pthread_cond_broadcast(&cv);
-	pthread_mutex_unlock(&mtx);
-}
-
-void Wait(void)
-{
-	pthread_mutex_lock(&mtx);
-	while(sync == 0)
-		pthread_cond_wait(&cv, &mtx);
-	pthread_mutex_unlock(&mtx);
-}
 */
 import "C"

コアとなるコードの解説

変更の核心は、C言語のコメントブロック内で行われています。

  1. #include <pthread.h> の削除:

    • 以前はPOSIXスレッドAPIを使用するために pthread.h をインクルードしていました。この行が削除されたことで、pthread ライブラリへの依存がなくなりました。
  2. pthread_mutex_tpthread_cond_t の削除:

    • pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;pthread_cond_t cv = PTHREAD_COND_INITIALIZER; は、それぞれミューテックスと条件変数を初期化する行でした。これらが削除されたことで、pthread 関連の同期プリミティブが使用されなくなりました。
  3. Notify 関数の変更:

    • 変更前: pthread_mutex_lockpthread_mutex_unlocksync 変数の更新を保護し、pthread_cond_broadcast で待機中のスレッドに通知していました。
    • 変更後: __sync_fetch_and_add(&sync, 1); に置き換えられました。これは sync 変数をアトミックに1増加させる操作です。このテストの文脈では、sync が0から非0に変化すれば十分であり、アトミック操作によって安全にその状態変化を保証できます。
  4. Wait 関数の変更:

    • 変更前: pthread_mutex_lockpthread_mutex_unlocksync 変数の読み取りを保護し、pthread_cond_waitsync が0の間、スレッドを待機させていました。
    • 変更後: while(__sync_fetch_and_add(&sync, 0) == 0) {} というビジーループに置き換えられました。__sync_fetch_and_add(&sync, 0)sync の値をアトミックに読み取ります。ループは sync の値が0でなくなるまで継続します。これは、Notify 関数によって sync が更新されるのを待つためのシンプルなビジーウェイトメカニズムです。テストコードでは、このようなシンプルな同期が許容される場合があります。

これらの変更により、テストコードは pthread の複雑な同期メカニズムから解放され、より直接的で軽量なアトミック操作による同期に移行しました。

関連リンク

参考にした情報源リンク

  • コミット情報から抽出したデータ
  • Go言語の公式ドキュメント
  • GCCのドキュメント
  • POSIXスレッドに関する一般的な知識
  • データ競合とアトミック操作に関する一般的なプログラミング知識
  • Go言語の課題追跡システム(当時のGoogle Codeの可能性)に関する一般的な情報(ただし、特定の課題 #4721 の詳細な内容は確認できませんでした)