Print in Order

Event同期による O(1) スレッド順序制御

アルゴリズム概要

問題説明

3つのスレッドが並行に起動し、それぞれ first()second()third() を呼び出します。スレッドの起動順序は不定ですが、出力は必ず "firstsecondthird" の順序を保証する必要があります。

入出力例

例1: nums = [1, 2, 3]

出力: "firstsecondthird"

例2: nums = [1, 3, 2]

出力: "firstsecondthird"

→ Thread CはThread Bを待機、正しい順序を保証

主要ポイント

  • 時間計算量: O(1) - 各メソッドは定数時間操作
  • 空間計算量: O(1) - 固定サイズの同期オブジェクト2個
  • 同期方式: threading.Event で効率的な待機

ステップバイステップ解説

Python実装

from threading import Event

class Foo:
    __slots__ = ('e1', 'e2')

    def __init__(self) -> None:
        self.e1 = Event()  # first() 完了通知
        self.e2 = Event()  # second() 完了通知

    def first(self, printFirst) -> None:
        printFirst()
        self.e1.set()  # second() の待機を解除

    def second(self, printSecond) -> None:
        self.e1.wait()  # first() の完了を待機
        printSecond()
        self.e2.set()  # third() の待機を解除

    def third(self, printThird) -> None:
        self.e2.wait()  # second() の完了を待機
        printThird()

フローチャート

Thread A (first) Thread B (second) Thread C (third) 起動 printFirst() e1.set() 通知 起動 e1.wait() 待機中... 解除 printSecond() e2.set() 通知 起動 e2.wait() 待機中... 解除 printThird() 出力結果 "firstsecondthird"

フローの説明:
1. Thread A: first() を即座に実行し、e1 をセット
2. Thread B: e1 を待機 → 解除後 second() 実行、e2 をセット
3. Thread C: e2 を待機 → 解除後 third() を実行

計算量分析

手法 時間計算量 空間計算量 特徴
Event(本実装) O(1) O(1) シンプル・高速・推奨
Lock/Mutex O(1) O(1) やや複雑
Condition Variable O(1) O(1) 汎用的だが冗長
Semaphore O(1) O(1) カウント機能あり

なぜ Event が最適か

  • ビジーウェイトなし: OSレベルで効率的にスリープ
  • __slots__: インスタンス辞書を排除しメモリ最適化
  • DAG構造: 一方向依存でデッドロック不可能