ルール
確保 スレッドセーフ アクセス への 共有 状態にアクセスできるようにする。
共有 ミュータブル 状態 アクセス 複数の 複数の スレッド
同期なし 同期 原因 レース 競合状態 そして 実行時エラー エラーを引き起こす。
対応言語 Python、 Java C#はじめに
複数のスレッドが同期を取らずに共有変数にアクセスしたり変更したりすると、競合状態が発生する。最終的な値は予測不可能なスレッドの実行タイミングに依存し、データの破損や不正な計算、ランタイム・エラーにつながる。ロックのない複数のスレッドによってインクリメントされたカウンターは、スレッドが古い値を読み込んでインクリメントし、競合する結果を書き戻すため、更新を見逃すことになる。
なぜそれが重要なのか
データ破損と不正確な結果:レース状態は、値の一貫性がなくなったり、不正確になったりするサイレント・データ破損を引き起こす。口座残高が間違ったり、在庫数がマイナスになったり、集計された統計値が破損したりします。これらのバグはスレッドの正確なタイミングに依存するため、再現が困難です。
システムの不安定性:共有状態への非同期アクセスはアプリケーションをクラッシュさせる可能性がある。あるスレッドがデータ構造を変更している間に別のスレッドがそれを読み込んでしまい、ヌル・ポインタ・エラーやインデックス・アウト・オブ・バウンズなどの例外が発生する可能性がある。実稼働環境では、これらは負荷がかかると断続的なクラッシュとして現れます。
デバッグの複雑さ:レースコンディションは非決定論的であるため、デバッグが難しいことで有名である。シングルスレッドのテストや低負荷の環境ではバグが現れないかもしれません。再現には特定のスレッドインターリーブが必要ですが、それを強制するのは難しく、問題がランダムに現れたり消えたりします。
コード例
非準拠:
class BankAccount:
def __init__(self):
self.balance = 0
def deposit(self, amount):
current = self.balance
# レース条件: 別のスレッドがここで残高を変更できる
time.sleep(0.001) # 処理時間をシミュレート
self.balance = current + amount
def withdraw(self, amount):
if self.balance >= amount:
現在の残高 = self.balance
time.sleep(0.001)
self.balance = current - amount
return True
return False
なぜ間違っているのか:複数のスレッドが同時にdeposit()やwithdraw()を呼び出すと、競合状態が発生する。100ドルずつ入金する2つのスレッドが、ともに残高を0ドルとして読み込んだ後、ともに100ドルを書き込んだ結果、最終的な残高は200ドルではなく100ドルになってしまうかもしれない。
✅ 準拠:
インポート・スレッディング
class BankAccount:
def __init__(self):
self.__balance = 0
self.__lock = threading.Lock()
@property
def balance(self):
with self.__lock:
return self.__balance
def deposit(self, amount):
with self.__lock:
current = self.__balance
time.sleep(0.001)
self.__balance = current + amount
def withdraw(self, amount):
with self.__lock:
if self.__balance >= amount:
現在の残高 = self.__balance
time.sleep(0.001)
self.__balance = current - amount
return True
return False
なぜこれが重要なのか: 会社情報 threading.Lock() は、一度に1つのスレッドだけがバランスにアクセスすることを保証する。1つのスレッドがロックを保持すると、他のスレッドは待機し、同時修正を防ぎます。プライベート バランス 読み取り専用 プロパティ 外部コードがロック保護をバイパスするのを防ぎます。
結論
ロック、セマフォ、アトミック操作のような適切な同期プリミティブを使用して、共有されたすべての変更可能な状態を保護する。可能であれば、不変のデータ構造またはスレッドローカルストレージを優先する。同期が必要な場合は、競合を減らしパフォーマンスを向上させるために、クリティカルセクションを最小限にする。
.avif)
