スレッドから同じメモリ領域への同時アクセスを防止する
実行中のスレッドと同じメモリ領域にほかのスレッドがアクセスすることを防止するには,次の基本的な方法があります。
オブジェクトをロックする
- キャンバスのように Lock メソッドを持つオブジェクトの場合は,必要なときに Lock メソッドを呼び出してほかのオブジェクトのアクセスを禁止し,ロックが不要になれば Unlock を呼び出します。
- TThreadList.LockList(Delphi)または TThreadList::LockList()(C++)を呼び出すと,スレッドはリストオブジェクト TThreadList を使用できなくなります。ロックが不要になれば,TThreadList.UnlockList を呼び出します。
メモ: TCanvas.Lock や TThreadList.LockList は安全に呼び出すことができます。
クリティカルセクションを使用する
- TCriticalSection のグローバルインスタンスを作成します。
- グローバルメモリにアクセスする間,ほかのスレッドをロックアウトするには,Acquire メソッドを呼び出します。
- Release メソッドを呼び出すと,ほかのスレッドは Acquire を呼び出すことでメモリにアクセスできるようになります。次のコードには,グローバル変数 X と Y へのアクセスを禁止するグローバルクリティカル変数 LockXY があります。スレッドで X または Y を使用するには,次のように,クリティカルセクションへの呼び出しで囲む必要があります。
LockXY.Acquire; try X := X + 1; Y := sin(X); finally LockXY.Release end;
LockXY->Acquire(); try { x++; y = sin( x ); } __finally { LockXY->Release(); }
警告: クリティカルセクションは,すべてのスレッドがクリティカルセクションを使ってグローバルメモリにアクセスする場合にのみ機能します。そうでない場合は,同時アクセスの問題が発生します。
複数読み出し/排他的書き込みシンクロナイザを使用する
- 保護するグローバルメモリに関連付けられた TMultiReadExclusiveWriteSynchronizer のグローバルインスタンスを作成します。
- スレッドは,メモリから読み取る前に BeginRead を呼び出す必要があります。
- メモリからの読み取りを終了したら,スレッドは EndRead を呼び出す必要があります。
- スレッドは,メモリに書き込む前に BeginWrite を呼び出す必要があります。
- メモリへの書き込みを終了したら,スレッドは EndWrite を呼び出す必要があります。
警告: 複数読み出し/排他的書き込みシンクロナイザは,すべてのスレッドが,このシンクロナイザを使って関連するグローバルメモリにアクセスする場合にのみ機能します。そうでない場合は,同時アクセスの問題が発生します。