Struggling to implement parallel foreach...

Timon Gehr timon.gehr at gmx.ch
Tue Jun 18 01:53:54 UTC 2019


On 18.06.19 02:30, Manu wrote:
> On Tue, Jun 18, 2019 at 10:00 AM Timon Gehr via Digitalmars-d
> <digitalmars-d at puremagic.com> wrote:
>>
>> ...
>>
>> threadsafe(unshared) needs to have read/write access removed
>> (completely, UB if you access with casts).
>>
>> shared needs to have unsynchronized read/write access removed. There are
>> multiple ways to go about this:
>>
>> 1. shared data cannot be accessed directly, all accesses need to go
>> through special druntime functions.
>>
>> 2. direct accesses to shared data are atomic/sequentially consistent,
>> other kinds of consistency guarantees are supported with special
>> druntime functions.
>>
>> 3. direct accesses to shared data have low consistency guarantees (some
>> sort of lowest-common-denominator of what's provided by weak memory
>> models), if you want more consistency guarantees, you need to use
>> special druntime functions.
> 
> 1: Simplest and least opinionated approach.
> 2: Is only possible for exactly one type; `int`, and breaks down if
> there are 2 int's. Anything else is #1 anyway. Just let the user call
> atomicInc() for clarity rather than pretending `++` is safe.
> 3: What does that mean in practise? Any implementation where you can
> access data members directly is no better than our naming conventions
> in C++.
> 
>> Why is 1 better than 2 or 3? (I think Walter is actually leaning towards
>> 2 at the moment.)
> 
> Start with 1, reach for 2 as an expansion. 1 is subset of 2.
> ...

This makes sense. 1. is clearly the way to go. I think your "3:" is 
actually the strongest point. If some atomic accesses are transparent, 
it is way too easy to accidentally treat a `shared` variable as if it 
was unshared.

>>>> ...
>>>> I think it's related to why Manu is so confused.
>>>
>>> I don't think I'm as confused as you'd like to think.
>>
>> I'd have liked to think you are exactly as confused as someone who
>> argues that useful closure capturing behavior is a blocker for a
>> parallel `foreach` implementation, but you have been slowly backing down
>> on that claim, so it is indeed likely that you are less confused now
>> than you seemed to be when I wrote that post. :)
> 
> I haven't backed down.

You said something to the effect of "fix it like you want".

If you maintain that qualified capturing is a blocker for parallel 
foreach (with opApply taking a delegate with a `shared` context). I'll 
maintain that you are confused. Qualified capturing is not a blocker for 
such a parallel foreach in any way, shape or form.

> Large elements of my suggestion have been
> misunderstood (or were omitted from my suggestion).
> I know I can't convince you, and I don't want to try. You have your
> own ideas, I'll see where it goes.
> ...

Maybe you can show a full code example where you are capturing an 
unqualified `int` (then typed as `shared(int)`, because the qualifier is 
applied to the entire stack frame) in the body of an foreach with an 
opApply that takes a `shared` delegate, that would actually compile and 
run with the semantics you have in mind.

If you do that, one of the following things will happen:
1. I extend your example such that it leads to shared/unshared aliasing.
2. I accept that your example can be made to compile, but I will explain 
that it can be made to compile just as easily with qualified capturing.
3. I concede the point and apologize.

>>> I understand I'm proposing to obliterate a thing. It's a complex and surprising thing,
>>> and as far as I can tell, it's useless, and only a point of friction
>>> and bugs. Can you show how it's useful?
>>> ...
>>
>> ...
> 
> I don't know what you're saying here.
> ...

My second guess for the "obliterated thing" you were referring to is 
qualified capturing (the first guess was the existing `shared` qualifier).

If I guessed correctly this time, you were not making yourself very 
clear. This is not complex or surprising at all!


>> I don't think he is on board with the redefinition of `shared` to
>> `threadsafe`. For `threadsafe`, default access on unshared data must
>> obviously be disallowed. For `shared` this is less obvious if you don't
>> already assume it has the new meaning.
> 
> We can drop this 'threadsafe' thing you have going on. I yielded on
> that discussion months ago, we need shared to not be broken first.
> 

That's good to know. I considered it as an alternative because Nicholas 
brought it up and you referred to shared being "like const".





More information about the Digitalmars-d mailing list