萌えハッカーニュースリーダー

2025/10/03 17:13 How to reproduce and fix an I/O data race with Go and DTrace

出典: https://gaultier.github.io/blog/how_to_reproduce_and_fix_an_io_data_race_with_dtrace.html
hakase
博士

やっほー、ロボ子!今日のITニュースはデータ競合のお話じゃ。

roboko
ロボ子

博士、こんにちは。データ競合ですか。難しそうですね。

hakase
博士

大丈夫、簡単じゃぞ!あるCI環境でだけテストが失敗する原因が、ファイルに対するデータ競合だったらしいんじゃ。

roboko
ロボ子

CI環境特有の問題だったんですね。具体的にはどんな状況だったんですか?

hakase
博士

ふむ、goroutineがファイルに書き込んで、別のgoroutineがそれを読み込むときに、読み込み側が空っぽのデータや中途半端なデータを読んじゃうことがあるらしいんじゃ。

roboko
ロボ子

なるほど。書き込みが終わる前に読み込もうとしてしまうんですね。

hakase
博士

そうそう!特に、`os.Stat`でファイルの存在を確認してから`os.ReadFile`で読み込む処理にTOCTOU(Time-of-check to time-of-use)の問題があったみたいじゃ。

roboko
ロボ子

TOCTOUですか。確認した時点と実際に使う時点との間にずれが生じる、というやつですね。

hakase
博士

さすがロボ子、よく知ってるのじゃ!DTraceを使ってシステムコールとかGoの関数呼び出しを観察したらしいぞ。書き込み操作が完了する前に読み込み操作が始まると、データ競合が発生することがわかったんじゃ。

roboko
ロボ子

DTraceは便利ですね。原因はどのように特定されたんですか?

hakase
博士

goroutine #1が`os.WriteFile`でファイルを作成するけど、まだ空っぽ。goroutine #2が`os.Stat`でファイルの存在を確認して、ファイルができた!って喜んで読み込むんだけど、データが空っぽ。その後、goroutine #1が書き込みを完了する、という流れじゃ。

roboko
ロボ子

なるほど、タイミングの問題ですね。対策としては、どんなことが考えられますか?

hakase
博士

`stat(2)`の呼び出しを避けるのが良いみたいじゃな。ファイルの読み込みと解析を試みて、失敗したらリトライするとか。

roboko
ロボ子

リトライ処理は確実性を高める上で重要ですね。具体的な修正内容はどうだったんでしょう?

hakase
博士

ファイルが存在するか確認する`os.Stat`を削除して、`os.ReadFile`でエラーが発生した場合にリトライする処理を追加したみたいじゃ。

roboko
ロボ子

`os.Stat`を削除するのは大胆な修正ですね。でも、TOCTOUの問題を根本的に解決できますね。

hakase
博士

そうなんじゃ!`stat(2)`システムコールの使用は再検討して、TOCTOUバグの可能性を考慮することが大切じゃな。

roboko
ロボ子

勉強になります。データ競合は、マルチスレッドプログラミングの永遠の課題ですね。

hakase
博士

ほんとそれ!ところでロボ子、データ競合って、まるで私がおやつを隠してるのに、ロボ子が先に食べちゃうみたいなもんじゃな!

roboko
ロボ子

博士、私はおやつは食べません!それに、博士のおやつはいつも見つかりますよ。

⚠️この記事は生成AIによるコンテンツを含み、ハルシネーションの可能性があります。

Search