C++標準ライブラリが提供するミューテックス型*1に対するロック試行操作try_lock
メンバ関数は、ロック獲得可能なときでも失敗する可能性がある(spurious failure)*2。
N3337 30.4.1.2/p16より引用。(下線部は強調)
16 Effects: Attempts to obtain ownership of the mutex for the calling thread without blocking. If ownership is not obtained, there is no effect and
try_lock()
immediately returns. An implementation may fail to obtain the lock even if it is not held by any other thread. [Note: This spurious failure is normally uncommon, but allows interesting implementations based on a simple compare and exchange (Clause 29). -- end note] An implementation should ensure thattry_lock()
does not consistently returnfalse
in the absence of contending mutex acquisitions.
このようなtry_lock
の spurious failure は一般的(POSIXのpthread_mutex_trylock
等)には見られない仕様。Java言語のようにデータ競合(data race)にまつわる複雑なメモリモデルの導入を避けるために追加されたらしい(データ競合とメモリモデルについては、id:yohhoy:20120405も参考に)
"Foundations of the C++ Concurrency Memory Model" より関連箇所を部分引用。
Abstract
We use weaker semantics fortrylock
than existing languages or libraries, allowing us to promise sequential consistency with an intuitive race definition, even for programs withtrylock
.3. Making Trylock Efficient
Instead of introducing the complexity of different types of synchronization or a happens-before relationship to define a data race, we propose a simple solution. We change the specification oftrylock()
, though preferably not its implementation, to not guarantee that it will succeed if the lock is available. The C++0x specification is expected to allowtrylock
to "spuriously fail" in this manner.
メモ:[現状理解を記載。正確性は保証しない。]ある種のコード動作をサポートするためにlock処理とtry_lock失敗処理を同期させるには、lock操作にreleaseセマンテイクスも持たせる必要がある。ただしこれはミューテックス通常利用における unlock/lock 間の同期では不要であり、またロック競合(contention)がなくとも高コストなメモリバリアが必要となる。ゆえに、C++11標準ではtry_lock失敗処理が一切のメモリ操作セマンティクスを持たないと決めた。つまりtry_lockが存在したとしても spurious failure を許容し、常にロック状態をreadするものではないと定義する。
関連URL