[cpp-threads] High-level vs. low-level

Peter Dimov pdimov at mmltd.net
Tue Jul 11 00:19:20 BST 2006


Herb Sutter wrote:
> Peter Dimov wrote:
>> Boehm, Hans wrote:
>>> The high level interface does seem to buy you some useful
>>> properties:
>>>
>>> 1) Things like double-checked locking work with just a declaration
>>> change, as they do in Java.  My impression is that some people
>>> perceive this as close to a requirement.
>>>
>>> 2) It can be directly applied to struct of bit-fields and the like.
>>>
>>> 3) Parameterization w.r.t. ordering constraints, which can reduce
>>> the amount of required library code.
>>
>> Perhaps it does buy some people something; I'm not disputing that. I
>> have no interest in it, though. It doesn't seem to buy me anything.
>> :-)
>
> I got lost in the quoting. :-) I think you're saying you're
> uninterested in the high-level part, right?

Correct. I don't need it for any of the code I have written, write, or will 
write, and hence I've no incentive to implement it. I have also not observed 
demand for it. :-)

> I believe the "low-level part" means explicit use of acquire, release,
> and raw. Right? I have trouble thinking of (3) above as high-level,
> and so when I say "low-level" below I'll include (3) above.

I view (3) as orthogonal to the low:high level distinction. It mainly 
affects the implementation of the atomics library. The low-level part for me 
is where you say

    atomic_load_acq( &x );

or

    atomic_load<acq>( &x );

or even

    atomic_load( acq, &x );

with x being an ordinary int or POD.

> I suspect that the number of programmers who can program reliably
> using the low-level part approaches zero (highly probable outside
> this group, and possibly including some of us). I'm really concerned
> that not even rocket scientist programmers can consistently write
> low-lock code correctly when forced to program with explicit fences
> and/or explicit acquire/release decorations.

This may well be so, but the majority of programmers will never touch the 
atomic operations directly. They'll use a read_write_mutex, a 
concurrent_hash_map, a bounded_blocking_queue. The _implementation_ of these 
high-level components will use the atomics.

> Do people feel strongly that the low-level part is reliably
> programmable by humans? If so, I would like the opportunity to test
> this hypothesis empirically. In particular, I have in mind to select
> a few brief lock-free code examples (no more than half a dozen), each
> to be interpreted using (a) Java-style volatile semantics and (b)
> atomic<raw> or similar semantics, and then ask a set of freshmen and
> a set of experts (including the proponents of the low-level model) to
> answer questions about the examples. I suspect that for both groups,
> both response time and correctness will vary greatly between (a) and
> (b).

This would be an interesting test. I really don't believe that by spelling

    atomic_store_rel( &x, 2 );
    r1 = atomic_load_acq( &x );

as

    x = 2;
    r1 = x;

we will somehow make lock-free programming "accessible for the masses". 
Quite the opposite... we are presenting it in a familiar syntax, thereby 
(falsely IMO) implying accessibility. But the accessibility isn't there and 
will never be. :-)

FWIW, when I read your memory model examples, I had to mentally substitute 
the low-level equivalents before being able to even understand what the 
example is about. And to do that, I had to go read the atomic<> document to 
see what the semantics of x = 2 and r1 = x are when x is atomic. So for me, 
this "clarity" was a definite step backwards. But I may be atypical.

Anyway, I really didn't want to get into this discussion. I just want us to 
get the low-level part right, and I'm not particularly disturbed by the 
high-level part, as long as it's possible to ignore. (That last condition 
may prove problematic when people start using it and I have to make sense of 
their code, though.)

>>>> * I'd really like to see
>>>> atomic_decrement_<order1,nonzero>_<order2,zero>, or at least
>>>> atomic_decrement_release_acquire.
>
> Sorry if I missed it: What would these do?

This primitive is an atomic decrement that has different ordering properties 
depending on whether the new value of the count is zero or not (the specific 
case being release on nonzero, acquire on zero). This is what shared_ptr 
(and reference counting in general when the pointees can be mutable) needs.




More information about the cpp-threads mailing list