Date: Sun, 24 Nov 2024 09:13:31 +0000
On 24 November 2024 02:03:51 GMT, J Decker via Std-Discussion <std-discussion_at_[hidden]> wrote:
>https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1152r0.html#parret
>
>
>I have some datatype, which is a volatile list. What makes it volatile is
>that other threads can change the values associated with the list without
>any other threads being aware of the change. Primarily, what happens, when
>the objects are not defined as volatile, the optimizers can read the value
>early in a function, and then never read it again. The only meaning of
>volatile *I* knew of was 'read always'. Writes and locks and other
>unrelated things mentioned in the paper just confuse the issue. What I
>need is just a way to tell compiler optimizers 'hey don't be smart, if the
>code needs the value, get the value from the place specified.' Writes
>could be cached - but it's something the programmer would do. It(volatile)
>really has nothing to do atomics.
>
>---
>So what I end up with is say this is the existing type.
>
>typedef struct DataBlock volatile * volatile PDATALIST;
>
>Then the creation function is PDATALIST CreateDataList( size_t sz );
>and usage is PDATALIST pdl = CreateDataList( sizeof( int ) );
>or passed as a parameter to PDATALIST AddDataItem( PDATALIST*, POINTER );
>or int GetItemCount( PDATALIST );
>
>That's all great... but then with LLVM's deprecation warning what I end up
>having to do is
>
>
>
>typedef struct DataBlock volatile * volatile PDATALIST;
>typedef struct DataBlock volatile * PDATALIST_rval;
>
>PDATALIST_rval CreateDataList( size_t sz );
>PDATALIST_rval AddDataItem( PDATALIST*, POINTER );
>int GetItemCount( PDATALIST_rval, POINTER );
>
>PDATALIST pdl = CreateDataList( sizeof( int ) );
>
>- it becomes unobvious that one should use PDATALIST as the variable type,
>while the function that creates the list is a PDATALIST_rval.
>
>Hooray for features that improve(err diminish) code clarity?
>
>Maybe should have started with deprecating volatile in typedefs?
>
>How can I code that so it's not mixing a bunch of different types?
>PDATALIST_rval and PDATALIST, or any of the half dozen other thread-safe
>container types that have been implemented since the mid 90's? (and
>preferably without having to touch many thousands of instances of PLIST
><...> to make it PLIST volatile <...>)
>
>J
>
>Yes, I get it .... in the passing of the volatile variable, it ends up
>being a cached value in a register and loses the original reference... and
>technically the GetItemCount should take a PDATALIST* instead... but that's
>a short time of life of that image anyway, and subsequent calls would end
>up with the new list address anyway; and there's of course times where the
>value ends up cached for several instructions, but when it goes back over
>the line to use the value it gets read again.
>
>I feel that a case study for implications of this wasn't really done very
>well - but then - maybe the usage of multi-threading is just that much less
>than I think it should be that this didn't show up. None of this has
>anything to do with Atomics and the locking of such a structure - some of
>them are lock-free.
volatile is unsuitable for implementing thread-safe lock-free data structures, you should be using lock-free atomics for that.
Cheers,
Lénárd
>https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1152r0.html#parret
>
>
>I have some datatype, which is a volatile list. What makes it volatile is
>that other threads can change the values associated with the list without
>any other threads being aware of the change. Primarily, what happens, when
>the objects are not defined as volatile, the optimizers can read the value
>early in a function, and then never read it again. The only meaning of
>volatile *I* knew of was 'read always'. Writes and locks and other
>unrelated things mentioned in the paper just confuse the issue. What I
>need is just a way to tell compiler optimizers 'hey don't be smart, if the
>code needs the value, get the value from the place specified.' Writes
>could be cached - but it's something the programmer would do. It(volatile)
>really has nothing to do atomics.
>
>---
>So what I end up with is say this is the existing type.
>
>typedef struct DataBlock volatile * volatile PDATALIST;
>
>Then the creation function is PDATALIST CreateDataList( size_t sz );
>and usage is PDATALIST pdl = CreateDataList( sizeof( int ) );
>or passed as a parameter to PDATALIST AddDataItem( PDATALIST*, POINTER );
>or int GetItemCount( PDATALIST );
>
>That's all great... but then with LLVM's deprecation warning what I end up
>having to do is
>
>
>
>typedef struct DataBlock volatile * volatile PDATALIST;
>typedef struct DataBlock volatile * PDATALIST_rval;
>
>PDATALIST_rval CreateDataList( size_t sz );
>PDATALIST_rval AddDataItem( PDATALIST*, POINTER );
>int GetItemCount( PDATALIST_rval, POINTER );
>
>PDATALIST pdl = CreateDataList( sizeof( int ) );
>
>- it becomes unobvious that one should use PDATALIST as the variable type,
>while the function that creates the list is a PDATALIST_rval.
>
>Hooray for features that improve(err diminish) code clarity?
>
>Maybe should have started with deprecating volatile in typedefs?
>
>How can I code that so it's not mixing a bunch of different types?
>PDATALIST_rval and PDATALIST, or any of the half dozen other thread-safe
>container types that have been implemented since the mid 90's? (and
>preferably without having to touch many thousands of instances of PLIST
><...> to make it PLIST volatile <...>)
>
>J
>
>Yes, I get it .... in the passing of the volatile variable, it ends up
>being a cached value in a register and loses the original reference... and
>technically the GetItemCount should take a PDATALIST* instead... but that's
>a short time of life of that image anyway, and subsequent calls would end
>up with the new list address anyway; and there's of course times where the
>value ends up cached for several instructions, but when it goes back over
>the line to use the value it gets read again.
>
>I feel that a case study for implications of this wasn't really done very
>well - but then - maybe the usage of multi-threading is just that much less
>than I think it should be that this didn't show up. None of this has
>anything to do with Atomics and the locking of such a structure - some of
>them are lock-free.
volatile is unsuitable for implementing thread-safe lock-free data structures, you should be using lock-free atomics for that.
Cheers,
Lénárd
Received on 2024-11-24 09:13:35