bucket-sort logo bucket-sort

プログラミングとインフラエンジニアリングの覚え書き

  • Posts
  • About
  • Contact
  1. Home
  2. All Posts
  3. [C#] Interlockedの使い方

[C#] Interlockedの使い方

Mar 27, 2026 C# , .NET bucket-sort

マルチスレッドや非同期処理を扱っていると、「ただの counter++ ですら安全ではない」という話にぶつかります。シングルスレッドでは何の問題もない単純な変数更新が、複数のスレッドが絡んだ瞬間に壊れることがあります。

そのような場面で使うのが Interlocked クラスです。 これは 複数スレッドから共有される変数を、ロックなしで安全に更新するための仕組み です。

Interlockedとは何か

一言でいうと、 変数操作を途中で割り込まれない形で一発でやるためのクラス です。

ここで重要なのが「アトミック(不可分)操作」という考え方です。 つまり、途中で別スレッドに割り込まれず、ひとかたまりとして実行される操作です。

なぜ必要なのか

たとえば、次のようなインクリメントは一見安全に見えます。

counter++;

しかし実際には、これは1命令ではありません。概念的には、

  1. 値を読む
  2. 1足す
  3. 書き戻す

という3段階です。

この間に別スレッドが割り込むと、結果が壊れます。

Thread A: read 0
Thread B: read 0
Thread A: write 1
Thread B: write 1

本来は 2 になるべきところが、結果は 1 になります。 これが race condition の典型です。

基本の使い方

こうした問題に対して、Interlocked を使うと更新をアトミックにできます。

Interlocked.Increment(ref counter);

これによって、

  • 読み取り
  • 加算
  • 書き込み

がひとまとまりで実行されます。

よく使うメソッド

Increment / Decrement

Interlocked.Increment(ref counter);
Interlocked.Decrement(ref counter);

カウンタ更新の基本です。

Add

Interlocked.Add(ref counter, 5);

一定量だけ増減させたいときに使います。

Exchange

Interlocked.Exchange(ref value, newValue);

値を一気に入れ替えます。旧値も戻り値で得られます。

これはフラグ制御などで便利です。

if (Interlocked.Exchange(ref _flag, 1) == 0)
{
    // 初回だけ通す
}

CompareExchange

これは最重要メソッドです。

Interlocked.CompareExchange(ref value, newValue, expectedValue);

意味は、 今の値が expectedValue なら newValue に置き換える です。

これは Compare-And-Swap(CAS)と呼ばれる代表的な原子的操作です。

典型例:一度だけ実行したい

if (Interlocked.CompareExchange(ref _initialized, 1, 0) == 0)
{
    Initialize();
}

このコードは「まだ初期化されていないなら、自分が初期化担当になる」という意味です。

単純な if (_initialized == 0) ではレースになりますが、CompareExchange ならその判定と更新を一体で行えます。

lockとの違い

Interlocked と lock はどちらも同期のための道具ですが、向いている場面が違います。

項目 Interlocked lock
オーバーヘッド 小さい 大きい
単純な値操作 得意 使えるがやや大げさ
複雑な処理全体の保護 不向き 得意

つまり、

  • 単純な1変数操作 → Interlocked
  • 複数行の複雑な排他 → lock

という使い分けになります。

Interlockedでは守れないもの

ここは重要です。Interlocked は万能ではありません。

たとえば:

if (counter == 0)
{
    counter++;
}

これは判定と更新が分かれているので、単なる Increment では守れません。

この場合は、CompareExchange のようなメソッドで「条件付き更新」をアトミックに表現する必要があります。

また、参照型の複雑な状態全体を保護する用途にも向きません。 Interlocked が保証するのは基本的に1変数単位です。

メモリ可視性も重要

Interlocked は単に原子的に更新するだけでなく、メモリバリアも伴います。 つまり、他スレッドから見たときの可視性も保証されます。

この点は、マルチコアCPUやキャッシュの存在を考えるとかなり重要です。単純に「一発で更新する」だけではなく、「その更新が他のスレッドにもちゃんと見える」ことまで面倒を見てくれます。

典型的な使いどころ

向いている用途

  • カウンタ
  • フラグ切り替え
  • 初回だけ実行
  • 軽量なスレッド同期

たとえばログ件数、アクセス件数、処理中フラグなどは典型です。

まとめ

Interlocked は、複数スレッドから共有される単純な変数を、安全かつ軽量に更新するためのクラスです。counter++ のような一見単純な操作でも、マルチスレッドでは壊れることがあります。そうした場面で、ロックを使わずにアトミックな更新を実現できます。

押さえておきたいポイント

  • 単純な1変数操作に強い
  • Increment と CompareExchange が特に重要
  • 複雑な排他には向かない
  • 可視性の保証もある

「共有変数を安全に更新したいが、lock をかけるほどではない」という場面では、まず Interlocked を思い出すとよいと思います。

C# .NET
← Laravelのレート制限(throttle:5,1)とは何か Filament の dehydrated メソッドとは何か →

Related Posts

  • [C#] delegate と event の仕組みを整理する Apr 1, 2026
  • Pub/Sub パターンとは何か Mar 31, 2026
  • [C#] ImmutableHashSet<T>の使い方 Mar 26, 2026
  • [C#] HashSet<T>の使い方 Mar 25, 2026

Table of Contents

  • Interlockedとは何か
  • なぜ必要なのか
  • 基本の使い方
  • よく使うメソッド
    • Increment / Decrement
    • Add
    • Exchange
    • CompareExchange
  • 典型例:一度だけ実行したい
  • lockとの違い
  • Interlockedでは守れないもの
  • メモリ可視性も重要
  • 典型的な使いどころ
    • 向いている用途
  • まとめ
    • 押さえておきたいポイント

Recent Posts

  • Laravel の Event / Listener で Pub/Sub を実装する Apr 2, 2026
  • [C#] delegate と event の仕組みを整理する Apr 1, 2026
  • Pub/Sub パターンとは何か Mar 31, 2026
  • PHP/Laravel で値の状態を判定するヘルパ関数まとめ Mar 30, 2026
  • Filament の dehydrated メソッドとは何か Mar 29, 2026

Categories

  • AWS27
  • C#22
  • .NET20
  • Laravel16
  • Linux12
  • Apache8
  • MySQL8
  • PHP8
  • DynamoDB6
  • Nginx5
  • WordPress4
  • インフラ4
  • Hugo3
  • セキュリティ3
  • .NET Framework1
  • Aurora1
  • Filament1
  • Git1
  • SQS1

Tags

  • AWS
  • C#
  • .NET
  • Laravel
  • PHP
  • MySQL
  • セキュリティ
  • Linux
  • Apache
  • Code Snippet
  • DynamoDB
  • NoSQL
  • PHP-FPM
  • RDS
  • DoS
  • Nginx
  • Windows
  • WordPress
  • パフォーマンス
  • 監視
  • Amazon Linux 2023
  • CMS
  • Docker
  • Ipset
  • Iptables
  • OPCache
  • Webサーバー
  • 認可
  • Aurora
  • Blade
Powered by Hugo & Explore Theme.