[cpp-threads] Spurious failures of try_lock{_for}({rel_time}) vs. strong try_lock{_for}({rel_time})

Alexander Terekhov alexander.terekhov at gmail.com
Mon Dec 22 17:23:10 GMT 2008


Subject changed...

Was: Spurious failures of try_lock{_for}({rel_time}) vs. conditional
fence semantics

(Err.. forget conditional fence... but consider total order/write
atomicity for lock variables)

On Mon, Dec 22, 2008 at 12:48 PM, Alexander Terekhov
<alexander.terekhov at gmail.com> wrote:
> N2800's try_lock():
>
> "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."
>
> N2800's try_lock_for(rel_time):
>
> "Effects: The function attempts to obtain ownership of the mutex
> within the time specified by rel_time. If the time specified by
> rel_time is less than or equal to 0, the function attempts to obtain
> ownership without blocking (as if by calling try_lock())."
>
> seem to contradict POSIX:
>
> http://www.opengroup.org/onlinepubs/009695399/functions/pthread_mutex_trylock.html
>
> "The pthread_mutex_trylock() function shall be equivalent to
> pthread_mutex_lock(), except that if the mutex object referenced by
> mutex is currently locked (by any thread, including the current
> thread), the call shall return immediately."
>
> http://www.opengroup.org/onlinepubs/009695399/functions/pthread_mutex_timedlock.html
>
> "Under no circumstance shall the function fail with a timeout if the
> mutex can be locked immediately."
>
> Judging from the draft and also
>
> http://www.hpl.hp.com/techreports/2008/HPL-2008-56.pdf
>
> the primary intent behind introduction of spurious failures was to
> make unlock()->try_lock{_for}({rel_time}) "synchronize with"
> conditionally ("If try_lock() returns true, prior unlock() operations
> on the same object synchronize with (1.10) this operation.").
>
> But why insist on spurious failures for try_lock{_for}({rel_time})
> instead of simply saying that these operations provide the effect of
> atomic_thread_fence(memory_order_acquire) if mutex ownership is
> obtained, otherwise no fence effect
> (atomic_thread_fence(memory_order_relaxed) if you like)?

Err, I forgot that "acquire" fence is actually a bidirectional beast.
(And I didn't really mean for try_lock{_for}({rel_time} to impose a
bidirectional constraint.) Now I also note that N2800 itself notes
that

"[ Note: Since lock() does not synchronize with a failed subsequent
try_lock(), the visibility rules are weak enough that little would be
known about the state after a failure, even in the absence of spurious
failures. —end note ]"

That seems to invalidate rationale for spurious failures given in

http://www.hpl.hp.com/techreports/2008/HPL-2008-56.pdf

and the only reason to allow spurious failure is

(from N2800)

"[ Note: This spurious failure is normally uncommon, but allows
interesting implementations based on a simple compare_exchange (29).
—end note ]"

Well, I find it somewhat curious that write atomicity examples like
the one below with unlock() for stores and try_lock() for loads would
behave non-TSO for lock variables

(initially locks Y and Z both locked)

P1: Y.unlock();
P2: Z.unlock(); fence(seq_cst); a = Y.try_lock();
P3: b = Y.try_lock(); c = Z.try_lock();

(a=0, b=1, c=0 violates write atomicity)

even with seq_cst fence added in between try_lock()s on P3...

Is this feature really intentional?

(Contradiction to POSIX regarding spurious failures aside for a moment.)

I'd rather expect that the example above should behave TSO-ish even in
the absence of seq_cst fence on P3 (meaning that on e.g. Power,
try_lock() should perform validating LR-SC even in the case of
initially seeing 'locked' status in lock variable)...

So what am still missing here?

TIA.

regards,
alexander.



More information about the cpp-threads mailing list