On Thu, 10 Jan 2019 10:11:30 -0800 (PST)
michael.po...@gmail.com wrote:
> On Thursday, January 10, 2019 at 11:35:54 AM UTC-5, Chris Vine wrote:
> > According to the standard:
> >
> > "The execution of a program contains a data race if it contains two
> > potentially concurrent conflicting actions, at least one of which is
> > not atomic, and neither happens before the other, except for the
> > special case for signal handlers described below".
> >
> > and
> >
> > "Two expression evaluations conflict if one of them modifies a
> > memory location (4.4) and the other one reads or modifies the same
> > memory location."
> >
> > There is nothing wrong with having a buffer comprising an array of
> > non-atomic ints (or of non-atomic anything else) protected by some form
> > of synchronization such as a mutex or semaphore, including some custom
> > semaphore you have created yourself from memory barriers, atomic values
> > and spinlocks. The question to be asked is whether there is some
> > synchronization which prevents any non-atomic memory location being
> > modified concurrently with a read or another write.
>
> I agree with all that you said above. But that is out of the context of
> my original post which discusses an algorithm which simply does not need
> to "protect" an access to non-atomic data with the standard
> synchronization primitives and achieves the correctness by the very
> different means.
I was covering my bases. Your "Now, of course we do not need our
buffer to be an array of atomic memory cells, our protocol looks to
care well about all the possible conflicts and simultaneous access to
the buffer memory" seemed to involve some synchronization "protocol"
which obviated the need for atomics.
> > What you might be thinking of is avoiding spinlocks on values which are
> > atomic at the hardware level and doing what we used to do in the old
> > (pre-C++11 memory model) days and use volatile built-in types (say,
> > ints) which you know to be atomic at the hardware level, supplemented
> > as necessary by fences to ensure visibility on your platform.
>
> Well, I don't see if this is related to my post either. I don't care
> in my algorithm about spinlocks and if I cared, I would not have a
> problem to make a spinlock around a C++11 atomic data.
See above.
> > But if
> > you can do that you can achieve the identical effect with atomic ints
> > with relaxed memory ordering (including relaxed memory ordering with an
> > external memory barrier - there is a use for that). You can even (I
> > think) have a std::array of std::atomic ints or a std::atomic of
> > std::array of ints with relaxed memory ordering. (In the case of an
> > std::atomic array of ints you must ensure you have relaxed memory
> > ordering set for it, otherwise the implementation will insert a mutex
> > to protect the array, which you don't want).
> >
> > In other words, I think that anything you can do with volatile integer
> > types with additional fences can be done identically with a std::atomic
> > integer types with relaxed memory ordering and additional fences.
>
> Well... It is true I could implement "my" algorithm (known commonly as
> "seqlock") by defining my data buffer as an array of atomic types, say
> atomic<int> or atomic<char> then accessing it with memory_order_relaxed.
>
> But
>
> 1. the point is the standard does no give me any guarantee such an access
> have the same effectiveness as an access to non-atomic memory.
The standard provides no guarantee about volatile either as regards
threads, which is your only alternative if you have no mutual
exclusion and/or semaphores and/or spinlocks and don't trust
std::atomic. However, for built-in types which on the particular
platform in question are atomic at the hardware level, relaxed memory
ordering will involve no synchronization operations in practice.
Would it be nice to have something requiring that in the standard
instead of being left as a quality of implementation issue? Yes, I
think it would.
> 2. Also, I cannot use strcpy() or sprintf() to write into my buffer.
True.
> 3. Also, if my buffer is structured, say, has a format
>
> struct Buffer
> {
> std::atomic<int> a;
> std::atomic<double> ddd;
> }
>
> then access to the "ddd" may demand either mutex/spinlock or "bus locked"
> operation even for memory_order_relaxed model (surprise?) just to
> guarantee the atomicity.
Yes it might, but what alternative is there?
> So, there is no a reasonable and effective implementation here. And the
> cause is our buffer is simply NOT atomic by the algorithm design and
> that we need to make it atomic is the result of C++ memory mode
> limitations.
>
> As for using std::atomic<std::array<int,1000>>, this is simply extremelly
> non-effective, causes massive memory copying and sychronozation
> (mutex/spinlock) and cannot be considered as a resolution candidate at
> all.
Memory copying is something completely orthogonal to your original
posting so I don't really understand what your point here is. (Copying
an array would almost certainly require some explicit locking anyway).
In any event you could use plain arrays and rely on pointer decay to
avoid copying if you want to pass by pointer. Possibly also an array of
std::atomic<int> would suit you better than an atomic array of int. But
as I say I don't understand your point here.
However, the overarching issue is that an array of volatile ints will
have the same advantages and disadvantages as an array of
std::atomic<int> with relaxed memory ordering, save that the first is
not standard conforming (but works) and the second is standard
conforming and also works. The code emitted will be identical.