• Pre-main construction order in modules

    From Muttley@DastardlyHQ.org@3:633/280.2 to All on Sun Mar 30 19:57:54 2025
    I was curious about the order in which objects get constructed in modules before main gets called. It seems with both Clang and gcc its the order in which the modules were linked together to form the runnable binary so if
    the link order was m1.o m2.o then anything in m1 would get constructed first. Vice verca if you switch the order.

    Is this codified in the standard or is it left up to compiler and linker writers to decide how they order this?


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Richard Damon@3:633/280.2 to All on Sun Mar 30 22:21:14 2025
    On 3/30/25 4:57 AM, Muttley@DastardlyHQ.org wrote:
    I was curious about the order in which objects get constructed in modules before main gets called. It seems with both Clang and gcc its the order in which the modules were linked together to form the runnable binary so if
    the link order was m1.o m2.o then anything in m1 would get constructed first. Vice verca if you switch the order.

    Is this codified in the standard or is it left up to compiler and linker writers to decide how they order this?


    It is left explicitly undefined in the Standard.

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: i2pn2 (i2pn.org) (3:633/280.2@fidonet)
  • From James Kuyper@3:633/280.2 to All on Mon Mar 31 01:38:57 2025
    On 3/30/25 4:57 AM, Muttley@DastardlyHQ.org wrote:
    I was curious about the order in which objects get constructed in modules before main gets called. It seems with both Clang and gcc its the order in which the modules were linked together to form the runnable binary so if
    the link order was m1.o m2.o then anything in m1 would get constructed first. Vice verca if you switch the order.

    Is this codified in the standard or is it left up to compiler and linker writers to decide how they order this?

    Section 6.9.3.3 does in fact impose many constraints on the sequence in
    which non-local objects with static storage duration get initialized.
    However, all of the sequence requirements are only between objects
    defined in the same translation unit. Also, it's implementation-defined
    which of those initializations occur before the start of main().

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Muttley@DastardlyHQ.org@3:633/280.2 to All on Mon Mar 31 02:30:34 2025
    On Sun, 30 Mar 2025 10:38:57 -0400
    James Kuyper <jameskuyper@alumni.caltech.edu> wibbled:
    On 3/30/25 4:57 AM, Muttley@DastardlyHQ.org wrote:
    I was curious about the order in which objects get constructed in modules
    before main gets called. It seems with both Clang and gcc its the order in >> which the modules were linked together to form the runnable binary so if
    the link order was m1.o m2.o then anything in m1 would get constructed first.

    Vice verca if you switch the order.

    Is this codified in the standard or is it left up to compiler and linker
    writers to decide how they order this?

    Section 6.9.3.3 does in fact impose many constraints on the sequence in
    which non-local objects with static storage duration get initialized. >However, all of the sequence requirements are only between objects
    defined in the same translation unit. Also, it's implementation-defined
    which of those initializations occur before the start of main().

    Initialising global objects before main is an absolute must otherwise how
    are you expected to use them safely? They're not in the code for decoration.


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Muttley@DastardlyHQ.org@3:633/280.2 to All on Mon Mar 31 03:09:38 2025
    On Sun, 30 Mar 2025 15:59:05 GMT
    Mr Flibble <flibble@reddwarf.jmc.corp> wibbled:
    On Sun, 30 Mar 2025 15:30:34 +0000, Muttley wrote:

    On Sun, 30 Mar 2025 10:38:57 -0400 James Kuyper
    <jameskuyper@alumni.caltech.edu> wibbled:
    On 3/30/25 4:57 AM, Muttley@DastardlyHQ.org wrote:
    I was curious about the order in which objects get constructed in
    modules before main gets called. It seems with both Clang and gcc its
    the order in which the modules were linked together to form the
    runnable binary so if the link order was m1.o m2.o then anything in m1 >>>> would get constructed first.

    Vice verca if you switch the order.

    Is this codified in the standard or is it left up to compiler and
    linker writers to decide how they order this?

    Section 6.9.3.3 does in fact impose many constraints on the sequence in >>>which non-local objects with static storage duration get initialized. >>>However, all of the sequence requirements are only between objects >>>defined in the same translation unit. Also, it's implementation-defined >>>which of those initializations occur before the start of main().

    Initialising global objects before main is an absolute must otherwise
    how are you expected to use them safely? They're not in the code for
    decoration.

    Global variables are really bad, you are wrong to think it is OK to use >them.

    You're entitled to your opinion. I tend to use a few global objects, often singletons that contain most of the code. Having them global means I don't have to pass a reference into every damn function in one object that requires the other object.


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Muttley@DastardlyHQ.org@3:633/280.2 to All on Mon Mar 31 03:23:33 2025
    On Sun, 30 Mar 2025 16:17:04 GMT
    Mr Flibble <flibble@reddwarf.jmc.corp> wibbled:
    On Sun, 30 Mar 2025 16:09:38 +0000, Muttley wrote:
    You're entitled to your opinion. I tend to use a few global objects,
    often singletons that contain most of the code. Having them global means
    I don't have to pass a reference into every damn function in one object
    that requires the other object.

    Singletons don't have to be global objects if you use the Meyers Singleton >pattern.

    Never heard of it and don't particularly care. I write code to solve problems, not to subscribe to whatever structural paradigm is flavour of the month.


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Bonita Montero@3:633/280.2 to All on Mon Mar 31 04:56:27 2025
    Am 30.03.2025 um 18:22 schrieb Mr Flibble:
    On Sun, 30 Mar 2025 07:21:14 -0400, Richard Damon wrote:

    On 3/30/25 4:57 AM, Muttley@DastardlyHQ.org wrote:
    I was curious about the order in which objects get constructed in
    modules before main gets called. It seems with both Clang and gcc its
    the order in which the modules were linked together to form the
    runnable binary so if the link order was m1.o m2.o then anything in m1
    would get constructed first.
    Vice verca if you switch the order.

    Is this codified in the standard or is it left up to compiler and
    linker writers to decide how they order this?


    It is left explicitly undefined in the Standard.

    No, it is *unspecified* not *undefined*.

    LOL - idiot

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Bonita Montero@3:633/280.2 to All on Mon Mar 31 04:58:51 2025
    Am 30.03.2025 um 18:17 schrieb Mr Flibble:

    Singletons don't have to be global objects if you use the Meyers Singleton pattern.

    That nearly doesn't make a difference, everything is still in the
    BSS-segment.


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Bonita Montero@3:633/280.2 to All on Mon Mar 31 05:05:51 2025
    Am 30.03.2025 um 20:02 schrieb Mr Flibble:

    It makes all the difference as it is the standard way to avoid the initialisation order fiasco (the subject of this thread) but I wouldn't expect an ignorant troll such as yourself to know this.

    It doesn't help to prevent the static initialization order
    fiasco since the initialization order of static members is
    also not guaranteed across translation units.


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Bonita Montero@3:633/280.2 to All on Mon Mar 31 05:08:51 2025
    Am 30.03.2025 um 20:07 schrieb Mr Flibble:
    On Sun, 30 Mar 2025 20:05:51 +0200, Bonita Montero wrote:

    Am 30.03.2025 um 20:02 schrieb Mr Flibble:

    It makes all the difference as it is the standard way to avoid the
    initialisation order fiasco (the subject of this thread) but I wouldn't
    expect an ignorant troll such as yourself to know this.

    It doesn't help to prevent the static initialization order fiasco since
    the initialization order of static members is also not guaranteed across
    translation units.

    The Meyers Singleton does NOT involve static members; I suggest you go
    read up on what it actually involves rather than continue to make a fool
    of yourself.

    /Flibble

    What you mean is right, but that's not Meyers singleton: https://laristra.github.io/flecsi/src/developer-guide/patterns/meyers_singleton.html


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Bonita Montero@3:633/280.2 to All on Mon Mar 31 05:17:23 2025
    Am 30.03.2025 um 20:11 schrieb Mr Flibble:

    No what I meant was the Meyers Singleton which involves static local variables NOT static member variables which is what YOU thought it meant.

    static local variables need double-checked locked initialization.
    That's rather slow to just get a reference.


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Richard Damon@3:633/280.2 to All on Mon Mar 31 06:01:24 2025
    On 3/30/25 2:20 PM, Mr Flibble wrote:
    On Sun, 30 Mar 2025 20:17:23 +0200, Bonita Montero wrote:

    Am 30.03.2025 um 20:11 schrieb Mr Flibble:

    No what I meant was the Meyers Singleton which involves static local
    variables NOT static member variables which is what YOU thought it
    meant.

    static local variables need double-checked locked initialization.
    That's rather slow to just get a reference.

    But that is nevertheless what the Meyers Singleton involves. Static local initialisation has been threadsafe since C++11 and if performance is a concern then you can always cache the result in a reference downstream in
    any hot path that needs it.

    /Flibble

    Yes, my typical implementation is a global pointer (or static member of
    a class, not significantly different in function), which code can do a
    check for zero, if it sees it zero calls the generator function which
    sets the variable to the address of the local static variable.

    The check for zero needs no guard, as redundant calls to the function
    are harmless, costing only the extra interlocking operation, and will be limited to code that reaches that pointer within the time frame needed
    to initialize the object.

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: i2pn2 (i2pn.org) (3:633/280.2@fidonet)
  • From Richard Damon@3:633/280.2 to All on Mon Mar 31 06:05:08 2025
    On 3/30/25 12:23 PM, Muttley@DastardlyHQ.org wrote:
    On Sun, 30 Mar 2025 16:17:04 GMT
    Mr Flibble <flibble@reddwarf.jmc.corp> wibbled:
    On Sun, 30 Mar 2025 16:09:38 +0000, Muttley wrote:
    You're entitled to your opinion. I tend to use a few global objects,
    often singletons that contain most of the code. Having them global means >>> I don't have to pass a reference into every damn function in one object
    that requires the other object.

    Singletons don't have to be global objects if you use the Meyers Singleton >> pattern.

    Never heard of it and don't particularly care. I write code to solve problems,
    not to subscribe to whatever structural paradigm is flavour of the month.


    But it is a solution to the problem, so worth looking at.



    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: i2pn2 (i2pn.org) (3:633/280.2@fidonet)
  • From Bonita Montero@3:633/280.2 to All on Mon Mar 31 07:15:03 2025
    Am 30.03.2025 um 20:20 schrieb Mr Flibble:

    But that is nevertheless what the Meyers Singleton involves. Static local initialisation has been threadsafe since C++11 and if performance is a concern then you can always cache the result in a reference downstream in
    any hot path that needs it.

    With current implemention all C++ runtimes govern all station initia- lizations through a single mutex. That hurts if you have a constructor
    that takes longer, maybe because of a socket-connection which the code
    waits for.


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Mon Mar 31 07:57:47 2025
    On 3/30/2025 1:15 PM, Bonita Montero wrote:
    Am 30.03.2025 um 20:20 schrieb Mr Flibble:

    But that is nevertheless what the Meyers Singleton involves.˙ Static
    local
    initialisation has been threadsafe since C++11 and if performance is a
    concern then you can always cache the result in a reference downstream in
    any hot path that needs it.

    With current implemention all C++ runtimes govern all station˙ initia- lizations through a single mutex. That hurts if you have a constructor
    that takes longer, maybe because of a socket-connection which the code
    waits for.


    Creating threads, socket-connections before main is a bad idea...? ;^o

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Bonita Montero@3:633/280.2 to All on Mon Mar 31 16:37:12 2025
    Am 30.03.2025 um 22:57 schrieb Chris M. Thomasson:

    Creating threads, socket-connections before main is a bad idea...? ;^o

    Why ?


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Muttley@DastardlyHQ.org@3:633/280.2 to All on Mon Mar 31 19:20:53 2025
    On Sun, 30 Mar 2025 16:26:32 GMT
    Mr Flibble <flibble@reddwarf.jmc.corp> wibbled:
    On Sun, 30 Mar 2025 16:23:33 +0000, Muttley wrote:

    On Sun, 30 Mar 2025 16:17:04 GMT Mr Flibble <flibble@reddwarf.jmc.corp>
    wibbled:
    On Sun, 30 Mar 2025 16:09:38 +0000, Muttley wrote:
    You're entitled to your opinion. I tend to use a few global objects,
    often singletons that contain most of the code. Having them global
    means I don't have to pass a reference into every damn function in one >>>> object that requires the other object.

    Singletons don't have to be global objects if you use the Meyers >>>Singleton pattern.

    Never heard of it and don't particularly care. I write code to solve
    problems,
    not to subscribe to whatever structural paradigm is flavour of the
    month.

    The Meyers Singleton pattern has been around for decades, it certainly is >not "flavour of the month" and your ignorance of it is quite noobish - it
    is the standard way of avoiding the global variable initialisation order >fiasco.

    Had a look. Woooo, it uses statics, how cutting edge. Done that myself plenty of times without knowing it had a special name (kind of an obvious alternative approach but hey) but now I feel blessed that I can go around saying "Meyer Pattern" and have others look at me in amazement at my knowledge.


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Bonita Montero@3:633/280.2 to All on Mon Mar 31 19:46:57 2025
    Am 30.03.2025 um 18:26 schrieb Mr Flibble:

    The Meyers Singleton pattern has been around for decades, ..

    Decades are multiples of a decade, i.e. >= 20 years. But Meyer's
    singleton is possible since C++11, where static local initializations
    are thread-safe, that's 14 years ago.


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Paavo Helde@3:633/280.2 to All on Mon Mar 31 19:49:23 2025
    On 30.03.2025 18:30, Muttley@DastardlyHQ.org wrote:
    On Sun, 30 Mar 2025 10:38:57 -0400
    James Kuyper <jameskuyper@alumni.caltech.edu> wibbled:
    Section 6.9.3.3 does in fact impose many constraints on the sequence in
    which non-local objects with static storage duration get initialized.
    However, all of the sequence requirements are only between objects
    defined in the same translation unit. Also, it's implementation-defined
    which of those initializations occur before the start of main().

    Initialising global objects before main is an absolute must otherwise how
    are you expected to use them safely? They're not in the code for decoration.

    Initializing global objects before main is not possible with
    demand-loaded dynamically loaded libraries.

    IIRC this clause in the standard (that it's implementation-defined which static initializations occur before the start of main()) was introduced
    in C++11 when they got around to recognize the existence of shared
    libraries. To make the global static variables usable there is now
    another clause ([basic.start.dynamic]):

    "If [initialization] is deferred, it strongly happens before any non-initialization odr-use of any non-inline function or non-inline
    variable defined in the same translation unit as the variable to be initialized."

    In practice, it means it is a bad idea to expose global static variables directly from a TU or from a shared library, because it is tricky to
    tell when and if the exported address becomes safe to use, and this may
    change on a whim by the compiler version and optimization levels, etc. I
    think I have seen a compiler optimizing away the whole TU when it only contained static data and no functions with external linkage.


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Paavo Helde@3:633/280.2 to All on Mon Mar 31 19:56:35 2025
    On 31.03.2025 11:46, Bonita Montero wrote:
    Am 30.03.2025 um 18:26 schrieb Mr Flibble:

    The Meyers Singleton pattern has been around for decades, ..

    Decades are multiples of a decade, i.e. >= 20 years. But Meyer's
    singleton is possible since C++11, where static local initializations
    are thread-safe, that's 14 years ago.

    Before C++11 one had to just add their own synchronization for thread
    safety (assuming multi-threaded access was needed, which was not so
    often in the past).

    C++11 just made coding of a Meyer's singleton easier, that's all.


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Muttley@DastardlyHQ.org@3:633/280.2 to All on Mon Mar 31 20:09:01 2025
    On Mon, 31 Mar 2025 11:49:23 +0300
    Paavo Helde <eesnimi@osa.pri.ee> wibbled:
    On 30.03.2025 18:30, Muttley@DastardlyHQ.org wrote:
    On Sun, 30 Mar 2025 10:38:57 -0400
    James Kuyper <jameskuyper@alumni.caltech.edu> wibbled:
    Section 6.9.3.3 does in fact impose many constraints on the sequence in
    which non-local objects with static storage duration get initialized.
    However, all of the sequence requirements are only between objects
    defined in the same translation unit. Also, it's implementation-defined
    which of those initializations occur before the start of main().

    Initialising global objects before main is an absolute must otherwise how
    are you expected to use them safely? They're not in the code for decoration.

    Initializing global objects before main is not possible with
    demand-loaded dynamically loaded libraries.

    Well obviously, but thats not what I'm talking about. If myobj() is constructed in a linked .o file I expect it to be available and ready in main(). If not then when? Or are you just supposed to guess or hope for the best?


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Bonita Montero@3:633/280.2 to All on Mon Mar 31 20:11:58 2025
    Am 31.03.2025 um 10:56 schrieb Paavo Helde:

    Before C++11 one had to just add their own synchronization for thread
    safety (assuming multi-threaded access was needed, which was not so
    often in the past).
    C++11 just made coding of a Meyer's singleton easier, that's all.

    That's not that easy since it is undefined when a static local variable
    is initialized before C++11. You'd have to wrap it in a union and leave
    only member which is the object uninitialized. That's possible, but
    that's not Meyer's singleton.


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Richard Damon@3:633/280.2 to All on Mon Mar 31 22:22:42 2025
    On 3/31/25 4:46 AM, Bonita Montero wrote:
    Am 30.03.2025 um 18:26 schrieb Mr Flibble:

    The Meyers Singleton pattern has been around for decades, ..

    Decades are multiples of a decade, i.e. >= 20 years. But Meyer's
    singleton is possible since C++11, where static local initializations
    are thread-safe, that's 14 years ago.


    Prior to C++11, it was a valid method for the initialization problem for single threaded C++ code, which really was all that had C++ standard
    defined behavior.

    I seem to remember the technique being used in pre-standard C++ in the
    library to get around the initialization order problem.

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: i2pn2 (i2pn.org) (3:633/280.2@fidonet)
  • From Richard Damon@3:633/280.2 to All on Mon Mar 31 22:25:49 2025
    On 3/31/25 5:11 AM, Bonita Montero wrote:
    Am 31.03.2025 um 10:56 schrieb Paavo Helde:

    Before C++11 one had to just add their own synchronization for thread
    safety (assuming multi-threaded access was needed, which was not so
    often in the past).
    C++11 just made coding of a Meyer's singleton easier, that's all.

    That's not that easy since it is undefined when a static local variable
    is initialized before C++11. You'd have to wrap it in a union and leave
    only member which is the object uninitialized. That's possible, but
    that's not Meyer's singleton.


    No, I seem to remember that static FUNCTION LOCAL variables have always
    been initialize at the moment the function is first entered, after all,
    the constructor can take arguments that might not be known till then, so
    it can't be constructed before, and it needs to be constructed before
    you pass the decleration.

    As I said elsewhere, I seem to rememeber the standard runtime used this
    sort of trick to enforce object creation order.

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: i2pn2 (i2pn.org) (3:633/280.2@fidonet)
  • From Paavo Helde@3:633/280.2 to All on Mon Mar 31 23:26:30 2025
    On 31.03.2025 12:11, Bonita Montero wrote:
    Am 31.03.2025 um 10:56 schrieb Paavo Helde:

    Before C++11 one had to just add their own synchronization for thread
    safety (assuming multi-threaded access was needed, which was not so
    often in the past).
    C++11 just made coding of a Meyer's singleton easier, that's all.

    That's not that easy since it is undefined when a static local variable
    is initialized before C++11. You'd have to wrap it in a union and leave
    only member which is the object uninitialized. That's possible, but
    that's not Meyer's singleton.

    Thread synchronization has been possible since the introduction of
    threads. Otherwise they would not have been usable.

    An example of pre-C++11 thread-safe Meyer singleton:

    std::map<std::string, std::string>& GetGlobalMap() {

    // No dynamic initialization, so this is safe:
    static std::map<std::string, std::string>* pGlobal = NULL;

    // No dynamic initialization, so this is safe as well:
    static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

    // Initialize the global static if not yet initialized.
    pthread_mutex_lock(&mutex);
    if (!pGlobal) {
    pGlobal = new std::map<std::string, std::string>();
    }
    pthread_mutex_unlock(&mutex);
    return *pGlobal;
    }



    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Bonita Montero@3:633/280.2 to All on Mon Mar 31 23:32:14 2025
    Am 31.03.2025 um 14:26 schrieb Paavo Helde:

    An example of pre-C++11 thread-safe Meyer singleton:

    std::map<std::string, std::string>& GetGlobalMap() {

    ˙˙˙ // No dynamic initialization, so this is safe:
    ˙˙˙ static std::map<std::string, std::string>* pGlobal = NULL;

    ˙˙˙ // No dynamic initialization, so this is safe as well:
    ˙˙˙ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

    ˙˙˙ // Initialize the global static if not yet initialized.
    ˙˙˙ pthread_mutex_lock(&mutex);
    ˙˙˙ if (!pGlobal) {
    ˙˙˙˙˙˙˙ pGlobal = new std::map<std::string, std::string>();
    ˙˙˙ }
    ˙˙˙ pthread_mutex_unlock(&mutex);
    ˙˙˙ return *pGlobal;
    }

    That's rather slow. Double-checked locking as implemented for
    all static locals with current runtimes is much more efficient.

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Paavo Helde@3:633/280.2 to All on Mon Mar 31 23:39:53 2025
    On 31.03.2025 12:09, Muttley@DastardlyHQ.org wrote:
    On Mon, 31 Mar 2025 11:49:23 +0300
    Paavo Helde <eesnimi@osa.pri.ee> wibbled:
    On 30.03.2025 18:30, Muttley@DastardlyHQ.org wrote:
    On Sun, 30 Mar 2025 10:38:57 -0400
    James Kuyper <jameskuyper@alumni.caltech.edu> wibbled:
    Section 6.9.3.3 does in fact impose many constraints on the sequence in >>>> which non-local objects with static storage duration get initialized.
    However, all of the sequence requirements are only between objects
    defined in the same translation unit. Also, it's implementation-defined >>>> which of those initializations occur before the start of main().

    Initialising global objects before main is an absolute must otherwise how >>> are you expected to use them safely? They're not in the code for decoration.

    Initializing global objects before main is not possible with
    demand-loaded dynamically loaded libraries.

    Well obviously, but thats not what I'm talking about. If myobj() is constructed
    in a linked .o file I expect it to be available and ready in main(). If not then when? Or are you just supposed to guess or hope for the best?

    The standard does not talk specifically about dynamic libraries, so the
    same rules apply for the main program. This means the same quote you
    snipped is relevant to your myobj as well:

    "If [initialization] is deferred, it strongly happens before any non-initialization odr-use of any non-inline function or non-inline
    variable defined in the same translation unit as the variable to be initialized."

    The keyword here is "non-initialization use". If you access your myobj
    from main() it would be a non-initialization use, which is guaranteed to trigger the needed initialization if needed, so everything will work fine.


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Paavo Helde@3:633/280.2 to All on Mon Mar 31 23:44:48 2025
    On 31.03.2025 15:32, Bonita Montero wrote:
    Am 31.03.2025 um 14:26 schrieb Paavo Helde:

    An example of pre-C++11 thread-safe Meyer singleton:

    std::map<std::string, std::string>& GetGlobalMap() {

    ˙˙˙˙ // No dynamic initialization, so this is safe:
    ˙˙˙˙ static std::map<std::string, std::string>* pGlobal = NULL;

    ˙˙˙˙ // No dynamic initialization, so this is safe as well:
    ˙˙˙˙ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

    ˙˙˙˙ // Initialize the global static if not yet initialized.
    ˙˙˙˙ pthread_mutex_lock(&mutex);
    ˙˙˙˙ if (!pGlobal) {
    ˙˙˙˙˙˙˙˙ pGlobal = new std::map<std::string, std::string>();
    ˙˙˙˙ }
    ˙˙˙˙ pthread_mutex_unlock(&mutex);
    ˙˙˙˙ return *pGlobal;
    }

    That's rather slow. Double-checked locking as implemented for
    all static locals with current runtimes is much more efficient.

    Sure. That's why one should not call such a function from inside a
    million iteration loop. But it would often be possible to call it before
    the loop and use the returned reference million times inside the loop.


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Muttley@DastardlyHQ.org@3:633/280.2 to All on Tue Apr 1 01:01:09 2025
    On Mon, 31 Mar 2025 15:39:53 +0300
    Paavo Helde <eesnimi@osa.pri.ee> wibbled:
    On 31.03.2025 12:09, Muttley@DastardlyHQ.org wrote:
    "If [initialization] is deferred, it strongly happens before any >non-initialization odr-use of any non-inline function or non-inline
    variable defined in the same translation unit as the variable to be >initialized."

    Who writes this stuff? Its borderline gibberish.

    The keyword here is "non-initialization use". If you access your myobj
    from main() it would be a non-initialization use, which is guaranteed to >trigger the needed initialization if needed, so everything will work fine.

    Not necessarily. What it the constructor of one object opened a network
    socket but that object wasn't touched again until something else in the
    program tried to loop back to that socket?


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Scott Lurndal@3:633/280.2 to All on Tue Apr 1 01:15:35 2025
    Reply-To: slp53@pacbell.net

    Paavo Helde <eesnimi@osa.pri.ee> writes:
    On 30.03.2025 18:30, Muttley@DastardlyHQ.org wrote:
    On Sun, 30 Mar 2025 10:38:57 -0400
    James Kuyper <jameskuyper@alumni.caltech.edu> wibbled:
    Section 6.9.3.3 does in fact impose many constraints on the sequence in
    which non-local objects with static storage duration get initialized.
    However, all of the sequence requirements are only between objects
    defined in the same translation unit. Also, it's implementation-defined
    which of those initializations occur before the start of main().

    Initialising global objects before main is an absolute must otherwise how
    are you expected to use them safely? They're not in the code for decoration.

    Initializing global objects before main is not possible with
    demand-loaded dynamically loaded libraries.

    Which are initialized as the library is loaded. Much the
    same effect as implementing before main.


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: UsenetServer - www.usenetserver.com (3:633/280.2@fidonet)
  • From James Kuyper@3:633/280.2 to All on Tue Apr 1 01:29:39 2025
    On 30.03.2025 18:30, Muttley@DastardlyHQ.org wrote:
    On Sun, 30 Mar 2025 10:38:57 -0400
    James Kuyper <jameskuyper@alumni.caltech.edu> wibbled:
    Section 6.9.3.3 does in fact impose many constraints on the sequence in
    which non-local objects with static storage duration get initialized.
    However, all of the sequence requirements are only between objects
    defined in the same translation unit. Also, it's implementation-defined
    which of those initializations occur before the start of main().

    Initialising global objects before main is an absolute must otherwise how
    are you expected to use them safely? They're not in the code for decoration.

    "If it [initialization] is deferred, it strongly happens before any non-initialization odr-use of any non-inline function or non-inline
    variable defined in the same translation unit as the variable to be initialized.47 It is implementation-defined in which threads and at
    which points in the program such deferred dynamic initialization
    occurs." (6.9.3.3p5).

    Therefore, what you need to do is make sure that the object has been initialized is to access it from a function defined in the same
    translation unit.

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Bonita Montero@3:633/280.2 to All on Tue Apr 1 01:47:05 2025
    Am 31.03.2025 um 16:15 schrieb Scott Lurndal:

    Which are initialized as the library is loaded. Much the
    same effect as implementing before main.

    It looks somewhat strange to me to get the address of an export which
    is not a function with dladdr or GetProcAddress. I think the usual case
    would be that the dynamic library uses global objects for its own use.


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Paavo Helde@3:633/280.2 to All on Tue Apr 1 04:06:08 2025
    On 31.03.2025 17:01, Muttley@DastardlyHQ.org wrote:
    On Mon, 31 Mar 2025 15:39:53 +0300
    Paavo Helde <eesnimi@osa.pri.ee> wibbled:
    On 31.03.2025 12:09, Muttley@DastardlyHQ.org wrote:
    "If [initialization] is deferred, it strongly happens before any
    non-initialization odr-use of any non-inline function or non-inline
    variable defined in the same translation unit as the variable to be
    initialized."

    Who writes this stuff? Its borderline gibberish.

    The keyword here is "non-initialization use". If you access your myobj >>from main() it would be a non-initialization use, which is guaranteed to
    trigger the needed initialization if needed, so everything will work fine.

    Not necessarily. What it the constructor of one object opened a network socket but that object wasn't touched again until something else in the program tried to loop back to that socket?

    The constructor of the object is not guaranteed to run if the object nor anything else in its TU is not accessed from outside. It means the
    socket might not be opened.

    And no, trying to access the object via a network socket does not
    qualify as "non-initialization odr-use" of the object, as far as the C++ standard is concerned ;-)



    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From James Kuyper@3:633/280.2 to All on Tue Apr 1 10:42:48 2025
    On 31.03.2025 17:01, Muttley@DastardlyHQ.org wrote:
    On Mon, 31 Mar 2025 15:39:53 +0300
    Paavo Helde <eesnimi@osa.pri.ee> wibbled:
    On 31.03.2025 12:09, Muttley@DastardlyHQ.org wrote:
    "If [initialization] is deferred, it strongly happens before any
    non-initialization odr-use of any non-inline function or non-inline
    variable defined in the same translation unit as the variable to be
    initialized."

    Who writes this stuff? Its borderline gibberish.

    Keep in mind that the key thing that makes this seem like gibberish is
    the use of precisely defined technical jargon, which is used for the
    same reason that jargon is used in many other contexts: it has a more
    precisely specified meaning than more informal wording would have had.

    Key pieces of jargon: "strongly happens before", "non-initialization", "odr-use", "translation unit". If there's anything you don't understand
    about that clause, it's probably based in unfamiliarity with such phrases.




    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Jakob Bohm@3:633/280.2 to All on Tue Apr 1 15:06:11 2025
    On 2025-03-31 14:32, Bonita Montero wrote:
    Am 31.03.2025 um 14:26 schrieb Paavo Helde:

    An example of pre-C++11 thread-safe Meyer singleton:

    std::map<std::string, std::string>& GetGlobalMap() {

    ˙˙˙˙ // No dynamic initialization, so this is safe:
    ˙˙˙˙ static std::map<std::string, std::string>* pGlobal = NULL;

    ˙˙˙˙ // No dynamic initialization, so this is safe as well:
    ˙˙˙˙ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

    ˙˙˙˙ // Initialize the global static if not yet initialized.
    ˙˙˙˙ pthread_mutex_lock(&mutex);
    ˙˙˙˙ if (!pGlobal) {
    ˙˙˙˙˙˙˙˙ pGlobal = new std::map<std::string, std::string>();
    ˙˙˙˙ }
    ˙˙˙˙ pthread_mutex_unlock(&mutex);
    ˙˙˙˙ return *pGlobal;
    }

    That's rather slow. Double-checked locking as implemented for
    all static locals with current runtimes is much more efficient.

    Artificial locking around ALL static locals as implemented by some
    modern compilers is highly wasteful as in most code, the code
    structure already ensures a single thread will be the first to
    execute that initialization/construction, often one of the threads
    in the compiler itself.

    That locking by compilers seem to be the result of someone in the C++
    ctte wanting to take over every OS feature that used to be out of
    scope for system programming languages like C/C++ . It also makes it unnecessarily harder to use the system compiler to implement the lower
    level code that exists at a more fundamental / portable level than
    silly textbook examples .


    Enjoy

    Jakob

    --
    Jakob Bohm, MSc.Eng., I speak only for myself, not my company
    This public discussion message is non-binding and may contain errors
    All trademarks and other things belong to their owners, if any.

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: Privat (3:633/280.2@fidonet)
  • From Jakob Bohm@3:633/280.2 to All on Tue Apr 1 15:29:14 2025
    On 2025-03-31 16:29, James Kuyper wrote:
    On 30.03.2025 18:30, Muttley@DastardlyHQ.org wrote:
    On Sun, 30 Mar 2025 10:38:57 -0400
    James Kuyper <jameskuyper@alumni.caltech.edu> wibbled:
    Section 6.9.3.3 does in fact impose many constraints on the sequence in
    which non-local objects with static storage duration get initialized.
    However, all of the sequence requirements are only between objects
    defined in the same translation unit. Also, it's implementation-defined
    which of those initializations occur before the start of main().

    Initialising global objects before main is an absolute must otherwise how
    are you expected to use them safely? They're not in the code for decoration.

    "If it [initialization] is deferred, it strongly happens before any non-initialization odr-use of any non-inline function or non-inline
    variable defined in the same translation unit as the variable to be initialized.47 It is implementation-defined in which threads and at
    which points in the program such deferred dynamic initialization
    occurs." (6.9.3.3p5).

    Therefore, what you need to do is make sure that the object has been initialized is to access it from a function defined in the same
    translation unit.


    The literalist reading of that wording fails miserably if a real world
    program uses a global constructor/initializer to cause some desired
    imperative effect outside the C++ runtime state. Examples include
    setting the CPU clock frequency of a small system, outputting some kind
    of welcome message to the human user etc. etc.

    However treating the standard text as an imperfect description of
    traditional compiler techniques used for 2nd. Edition compilers makes
    much more sense . Those guarantee that all included global objects
    are constructed before the first line of the main/init function of the
    linker output unit (program, dll, driver, whatever) and destructed after
    the last line of the main/cleanup function of the same . Even if either
    of those functions are implicit default empty functions . Just like if
    those globals were member objects of an implied program class where main/init/cleanup are member/constructor/destructor functions .

    Note that my previous paragraph accepts the possibility of some global
    objects getting optimized away completely along with their compilation
    unit by things like using a static library containing those compilation
    units .


    Enjoy

    Jakob

    --
    Jakob Bohm, MSc.Eng., I speak only for myself, not my company
    This public discussion message is non-binding and may contain errors
    All trademarks and other things belong to their owners, if any.

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: Privat (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Tue Apr 1 15:54:53 2025
    On 3/30/2025 10:37 PM, Bonita Montero wrote:
    Am 30.03.2025 um 22:57 schrieb Chris M. Thomasson:

    Creating threads, socket-connections before main is a bad idea...? ;^o

    Why ?


    Is main all setup pre main?

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Bonita Montero@3:633/280.2 to All on Tue Apr 1 17:41:02 2025
    Am 01.04.2025 um 06:06 schrieb Jakob Bohm:

    Artificial locking around ALL static locals as implemented by some
    modern compilers is highly wasteful as in most code, the code
    structure already ensures a single thread will be the first to
    execute that initialization/construction, often one of the threads
    in the compiler itself.

    That locking by compilers seem to be the result of someone in the C++
    ctte wanting to take over every OS feature that used to be out of
    scope for system programming languages like C/C++ .˙ It also makes it unnecessarily harder to use the system compiler to implement the lower
    level code that exists at a more fundamental / portable level than
    silly textbook examples .

    Double-checked locking nearly costs nothing.


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Bonita Montero@3:633/280.2 to All on Tue Apr 1 17:41:23 2025
    Am 01.04.2025 um 06:54 schrieb Chris M. Thomasson:

    Is main all setup pre main?

    Pre-main.


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Tue Apr 1 18:00:56 2025
    On 3/31/2025 11:41 PM, Bonita Montero wrote:
    Am 01.04.2025 um 06:54 schrieb Chris M. Thomasson:

    Is main all setup pre main?

    Pre-main.


    Setting a lot of things up pre-main can lead to some issues... Waiting
    on a connection before main is called seems rather odd to me, ect...

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Muttley@DastardlyHQ.org@3:633/280.2 to All on Tue Apr 1 18:26:50 2025
    On Mon, 31 Mar 2025 19:42:48 -0400
    James Kuyper <jameskuyper@alumni.caltech.edu> wibbled:
    On 31.03.2025 17:01, Muttley@DastardlyHQ.org wrote:
    On Mon, 31 Mar 2025 15:39:53 +0300
    Paavo Helde <eesnimi@osa.pri.ee> wibbled:
    On 31.03.2025 12:09, Muttley@DastardlyHQ.org wrote:
    "If [initialization] is deferred, it strongly happens before any
    non-initialization odr-use of any non-inline function or non-inline
    variable defined in the same translation unit as the variable to be
    initialized."

    Who writes this stuff? Its borderline gibberish.

    Keep in mind that the key thing that makes this seem like gibberish is
    the use of precisely defined technical jargon, which is used for the
    same reason that jargon is used in many other contexts: it has a more >precisely specified meaning than more informal wording would have had.

    Key pieces of jargon: "strongly happens before", "non-initialization",

    "strongly happens before" is genuine gibberish. Either something happens before or it doesn't, the adverb is entirely superfluous.

    "odr-use", "translation unit". If there's anything you don't understand
    about that clause, it's probably based in unfamiliarity with such phrases.

    I'm a native english speaker and had to read it more than once to understand it. I feel sorry for people who's native language is not english trying to understand this crap.

    Yes this sort of language is similar to legalese, but with law it usually only applies to a given country so will be in the language of that country.


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Paavo Helde@3:633/280.2 to All on Tue Apr 1 19:41:01 2025
    On 01.04.2025 07:06, Jakob Bohm wrote:
    On 2025-03-31 14:32, Bonita Montero wrote:
    Am 31.03.2025 um 14:26 schrieb Paavo Helde:

    An example of pre-C++11 thread-safe Meyer singleton:

    std::map<std::string, std::string>& GetGlobalMap() {

    ˙˙˙˙ // No dynamic initialization, so this is safe:
    ˙˙˙˙ static std::map<std::string, std::string>* pGlobal = NULL;

    ˙˙˙˙ // No dynamic initialization, so this is safe as well:
    ˙˙˙˙ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

    ˙˙˙˙ // Initialize the global static if not yet initialized.
    ˙˙˙˙ pthread_mutex_lock(&mutex);
    ˙˙˙˙ if (!pGlobal) {
    ˙˙˙˙˙˙˙˙ pGlobal = new std::map<std::string, std::string>();
    ˙˙˙˙ }
    ˙˙˙˙ pthread_mutex_unlock(&mutex);
    ˙˙˙˙ return *pGlobal;
    }

    That's rather slow. Double-checked locking as implemented for
    all static locals with current runtimes is much more efficient.

    Artificial locking around ALL static locals as implemented by some
    modern compilers is highly wasteful as in most code, the code
    structure already ensures a single thread will be the first to
    execute that initialization/construction,

    The synchronization of static variable initialization (which may or may
    not involve locking) is demanded by the C++11 standard (so it is pretty portable) and makes it easier, faster, safer, and more maintainable to
    use statics in multithreaded C++ code (which is "most code" in my area).

    In an unlikely event this causes any measurable slowdown in a tight
    loop, a reference to the static variable can often be extracted before
    the loop.

    often one of the threads in the compiler itself.

    Sorry, cannot parse that sentence.

    That locking by compilers seem to be the result of someone in the C++
    ctte wanting to take over every OS feature that used to be out of
    scope for system programming languages like C/C++.
    ˙ It also makes it
    unnecessarily harder to use the system compiler to implement the lower
    level code that exists at a more fundamental / portable level than
    silly textbook examples .

    How comes? In some lower level code you one might just not use dynamic initialization of statics, which avoids any need of thread synchronization.

    If you do not know the differences between zero-initialization, constant initialization and dynamic initialization, then you are not in a
    position to implement any "lower level" code.



    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Paavo Helde@3:633/280.2 to All on Tue Apr 1 19:48:23 2025
    On 01.04.2025 10:26, Muttley@DastardlyHQ.org wrote:
    On Mon, 31 Mar 2025 19:42:48 -0400
    James Kuyper <jameskuyper@alumni.caltech.edu> wibbled:
    On 31.03.2025 17:01, Muttley@DastardlyHQ.org wrote:
    On Mon, 31 Mar 2025 15:39:53 +0300
    Paavo Helde <eesnimi@osa.pri.ee> wibbled:
    On 31.03.2025 12:09, Muttley@DastardlyHQ.org wrote:
    "If [initialization] is deferred, it strongly happens before any
    non-initialization odr-use of any non-inline function or non-inline
    variable defined in the same translation unit as the variable to be
    initialized."

    Who writes this stuff? Its borderline gibberish.

    Keep in mind that the key thing that makes this seem like gibberish is
    the use of precisely defined technical jargon, which is used for the
    same reason that jargon is used in many other contexts: it has a more
    precisely specified meaning than more informal wording would have had.

    Key pieces of jargon: "strongly happens before", "non-initialization",

    "strongly happens before" is genuine gibberish. Either something happens before
    or it doesn't, the adverb is entirely superfluous.

    Welcome to the 21-st century where out-of-sync CPU caches and pipelines
    are the norm.


    "odr-use", "translation unit". If there's anything you don't understand
    about that clause, it's probably based in unfamiliarity with such phrases.

    I'm a native english speaker and had to read it more than once to understand it.

    Somehow I suspect you have not understood much. For understanding the technical terms you need to read their definitions in the standard, not
    try to guess their meaning by an isolated usage example.



    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Muttley@DastardlyHQ.org@3:633/280.2 to All on Tue Apr 1 19:57:14 2025
    On Tue, 1 Apr 2025 11:48:23 +0300
    Paavo Helde <eesnimi@osa.pri.ee> wibbled:
    On 01.04.2025 10:26, Muttley@DastardlyHQ.org wrote:
    On Mon, 31 Mar 2025 19:42:48 -0400
    James Kuyper <jameskuyper@alumni.caltech.edu> wibbled:
    On 31.03.2025 17:01, Muttley@DastardlyHQ.org wrote:
    On Mon, 31 Mar 2025 15:39:53 +0300
    Paavo Helde <eesnimi@osa.pri.ee> wibbled:
    On 31.03.2025 12:09, Muttley@DastardlyHQ.org wrote:
    "If [initialization] is deferred, it strongly happens before any
    non-initialization odr-use of any non-inline function or non-inline
    variable defined in the same translation unit as the variable to be
    initialized."

    Who writes this stuff? Its borderline gibberish.

    Keep in mind that the key thing that makes this seem like gibberish is
    the use of precisely defined technical jargon, which is used for the
    same reason that jargon is used in many other contexts: it has a more
    precisely specified meaning than more informal wording would have had.

    Key pieces of jargon: "strongly happens before", "non-initialization",

    "strongly happens before" is genuine gibberish. Either something happens >before
    or it doesn't, the adverb is entirely superfluous.

    Welcome to the 21-st century where out-of-sync CPU caches and pipelines
    are the norm.

    Are you smoking something illegal? You're making less sense than that paragraph.

    I'm a native english speaker and had to read it more than once to understand >> it.

    Somehow I suspect you have not understood much. For understanding the >technical terms you need to read their definitions in the standard, not
    try to guess their meaning by an isolated usage example.

    Save your lame patronising for someone who cares and while you're at it
    mene vittuun itseäsi.




    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Paavo Helde@3:633/280.2 to All on Tue Apr 1 20:21:56 2025
    On 01.04.2025 11:57, Muttley@DastardlyHQ.org wrote:

    Save your lame patronising for someone who cares and while you're at it
    mene vittuun itse„si.

    Wrong language :-) Try again!



    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Bonita Montero@3:633/280.2 to All on Tue Apr 1 20:42:43 2025
    Am 01.04.2025 um 09:00 schrieb Chris M. Thomasson:

    Setting a lot of things up pre-main can lead to some issues... Waiting
    on a connection before main is called seems rather odd to me, ect...

    If it does happen anyway it doesn't matter when it happens.


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Fred. Zwarts@3:633/280.2 to All on Tue Apr 1 21:00:40 2025
    Op 01.apr.2025 om 11:42 schreef Bonita Montero:
    Am 01.04.2025 um 09:00 schrieb Chris M. Thomasson:

    Setting a lot of things up pre-main can lead to some issues... Waiting
    on a connection before main is called seems rather odd to me, ect...

    If it does happen anyway it doesn't matter when it happens.


    One may wonder why we still need a 'main'. Everything in main can be
    done in an static object.

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Muttley@DastardlyHQ.org@3:633/280.2 to All on Tue Apr 1 21:08:26 2025
    On Tue, 1 Apr 2025 12:21:56 +0300
    Paavo Helde <eesnimi@osa.pri.ee> wibbled:
    On 01.04.2025 11:57, Muttley@DastardlyHQ.org wrote:

    Save your lame patronising for someone who cares and while you're at it
    mene vittuun itseäsi.

    Wrong language :-) Try again!


    Oh well, I'm sure you can use google translate too.


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Michael S@3:633/280.2 to All on Tue Apr 1 21:12:47 2025
    On Tue, 1 Apr 2025 12:21:56 +0300
    Paavo Helde <eesnimi@osa.pri.ee> wrote:

    On 01.04.2025 11:57, Muttley@DastardlyHQ.org wrote:
    =20
    Save your lame patronising for someone who cares and while you're
    at it mene vittuun itse=C3=A4si. =20
    =20
    Wrong language :-) Try again!
    =20
    =20

    He is probably using Google Translate. Google Translate does not know
    how to say it in right language. So Muttley, being Muttley, had no
    choice but to select a closest language in which Google translate does
    know a translation.


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Michael S@3:633/280.2 to All on Tue Apr 1 21:20:44 2025
    On Tue, 1 Apr 2025 11:48:23 +0300
    Paavo Helde <eesnimi@osa.pri.ee> wrote:


    Welcome to the 21-st century where out-of-sync CPU caches and
    pipelines are the norm.



    It seems to me that saying that events are "strongly ordered" makes
    sense only when "weakly ordered" and "unordered" are not the same.
    In this particular case I don't see how exactly "weakly ordered"
    differs from "unordered".


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Muttley@DastardlyHQ.org@3:633/280.2 to All on Tue Apr 1 21:23:24 2025
    On Tue, 1 Apr 2025 13:12:47 +0300
    Michael S <already5chosen@yahoo.com> wibbled:
    On Tue, 1 Apr 2025 12:21:56 +0300
    Paavo Helde <eesnimi@osa.pri.ee> wrote:

    On 01.04.2025 11:57, Muttley@DastardlyHQ.org wrote:
    =20
    Save your lame patronising for someone who cares and while you're
    at it mene vittuun itse=C3=A4si. =20
    =20
    Wrong language :-) Try again!
    =20
    =20

    He is probably using Google Translate. Google Translate does not know
    how to say it in right language. So Muttley, being Muttley, had no
    choice but to select a closest language in which Google translate does
    know a translation.



    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Muttley@DastardlyHQ.org@3:633/280.2 to All on Tue Apr 1 21:27:06 2025
    On Tue, 1 Apr 2025 13:12:47 +0300
    Michael S <already5chosen@yahoo.com> wibbled:
    On Tue, 1 Apr 2025 12:21:56 +0300
    Paavo Helde <eesnimi@osa.pri.ee> wrote:

    On 01.04.2025 11:57, Muttley@DastardlyHQ.org wrote:
    =20
    Save your lame patronising for someone who cares and while you're
    at it mene vittuun itse=C3=A4si. =20
    =20
    Wrong language :-) Try again!
    =20
    =20

    He is probably using Google Translate. Google Translate does not know
    how to say it in right language. So Muttley, being Muttley, had no
    choice but to select a closest language in which Google translate does
    know a translation.

    Going by his name I assumed he was finnish but looking at his address now I suspect estonian. Right ballpark.


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Paavo Helde@3:633/280.2 to All on Tue Apr 1 21:33:43 2025
    On 01.04.2025 13:20, Michael S wrote:
    On Tue, 1 Apr 2025 11:48:23 +0300
    Paavo Helde <eesnimi@osa.pri.ee> wrote:


    Welcome to the 21-st century where out-of-sync CPU caches and
    pipelines are the norm.



    It seems to me that saying that events are "strongly ordered" makes
    sense only when "weakly ordered" and "unordered" are not the same.
    In this particular case I don't see how exactly "weakly ordered"
    differs from "unordered".

    The standard defines the terms "happens before", "simply happens
    before", and "strongly happens before". The standard does not contain
    phrases "strongly ordered" or "weakly ordered".



    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Muttley@DastardlyHQ.org@3:633/280.2 to All on Tue Apr 1 21:48:49 2025
    On Tue, 1 Apr 2025 13:33:43 +0300
    Paavo Helde <eesnimi@osa.pri.ee> wibbled:
    On 01.04.2025 13:20, Michael S wrote:
    On Tue, 1 Apr 2025 11:48:23 +0300
    Paavo Helde <eesnimi@osa.pri.ee> wrote:


    Welcome to the 21-st century where out-of-sync CPU caches and
    pipelines are the norm.



    It seems to me that saying that events are "strongly ordered" makes
    sense only when "weakly ordered" and "unordered" are not the same.
    In this particular case I don't see how exactly "weakly ordered"
    differs from "unordered".

    The standard defines the terms "happens before", "simply happens
    before", and "strongly happens before". The standard does not contain

    Those phrases all mean the same thing.



    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Bonita Montero@3:633/280.2 to All on Tue Apr 1 23:16:38 2025
    Am 01.04.2025 um 12:00 schrieb Fred. Zwarts:

    One may wonder why we still need a 'main'. Everything in main can be
    done in an static object.

    It's easier to define a main() since it needs less syntax than a class.

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Bonita Montero@3:633/280.2 to All on Wed Apr 2 01:03:38 2025
    Am 01.04.2025 um 14:16 schrieb Bonita Montero:

    Am 01.04.2025 um 12:00 schrieb Fred. Zwarts:

    One may wonder why we still need a 'main'. Everything in main can be
    done in an static object.

    It's easier to define a main() since it needs less syntax than a class.

    And more important: there might be other global objects which are
    initialized after this pseudo-"main()", but which are needed before.


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From James Kuyper@3:633/280.2 to All on Wed Apr 2 04:55:43 2025
    On 4/1/25 00:29, Jakob Bohm wrote:
    On 2025-03-31 16:29, James Kuyper wrote:
    ....
    "If it [initialization] is deferred, it strongly happens before any
    non-initialization odr-use of any non-inline function or non-inline
    variable defined in the same translation unit as the variable to be
    initialized.47 It is implementation-defined in which threads and at
    which points in the program such deferred dynamic initialization
    occurs." (6.9.3.3p5).

    Therefore, what you need to do is make sure that the object has been
    initialized is to access it from a function defined in the same
    translation unit.


    The literalist reading of that wording fails miserably if a real world program uses a global constructor/initializer to cause some desired imperative effect outside the C++ runtime state. Examples include
    setting the CPU clock frequency of a small system, outputting some kind
    of welcome message to the human user etc. etc.

    The wording describes what C++ does and does not require of an
    implementation. What actual implementations do is a different issue. If
    an implementation doesn't do what's required of it, it's non-conforming.
    If a program expects more than is required, the behavior of that code is undefined, which includes the possibility that the code will work
    exactly as intended if translated by an implementation that does, in
    fact, do more than what is required.

    However treating the standard text as an imperfect description of traditional compiler techniques used for 2nd. Edition compilers makes
    much more sense .

    No, that does not. The standard was never intended as a description of
    how compilers actually work, it was always intended to be a description
    of requirements on how they should work.

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From James Kuyper@3:633/280.2 to All on Wed Apr 2 05:32:54 2025
    On 01.04.2025 10:26, Muttley@DastardlyHQ.org wrote:
    On Mon, 31 Mar 2025 19:42:48 -0400
    James Kuyper <jameskuyper@alumni.caltech.edu> wibbled:
    On 31.03.2025 17:01, Muttley@DastardlyHQ.org wrote:
    On Mon, 31 Mar 2025 15:39:53 +0300
    Paavo Helde <eesnimi@osa.pri.ee> wibbled:
    On 31.03.2025 12:09, Muttley@DastardlyHQ.org wrote:
    "If [initialization] is deferred, it strongly happens before any
    non-initialization odr-use of any non-inline function or non-inline
    variable defined in the same translation unit as the variable to be
    initialized."

    Who writes this stuff? Its borderline gibberish.

    Keep in mind that the key thing that makes this seem like gibberish is
    the use of precisely defined technical jargon, which is used for the
    same reason that jargon is used in many other contexts: it has a more
    precisely specified meaning than more informal wording would have had.

    Key pieces of jargon: "strongly happens before", "non-initialization",

    "strongly happens before" is genuine gibberish. Either something happens before
    or it doesn't, the adverb is entirely superfluous.

    Terms are explicitly defined by the C++ standard precisely because their meaning cannot be inferred by using ordinary English to interpret the
    words that make them up. Both "happens before" and "strongly happens
    before" are separate pieces of C++ jargon, and the requirements for
    qualifying as "strongly happens before" are in fact stronger than those
    for "happens before".

    "An evaluation A happens before an evaluation B (or, equivalently, B
    happens after A) if:
    (10.1)— A is sequenced before B, or
    (10.2)— A inter-thread happens before B.
    The implementation shall ensure that no program execution demonstrates a
    cycle in the “happens before” relation. [Note: This cycle would
    otherwise be possible only through the use of consume operations. — end note]" (6.9.2.1p10).

    the first occurrence of "happens before" in that clause is in italics,
    an ISO convention indicating that it is a piece of specialized jargon
    whose definition is provided by the sentence in which it occurs. Note
    that "sequenced before" and "inter-thread happens before" are two other
    pieces of standard-defined jargon.

    "An evaluation A strongly happens before an evaluation D if, either
    (12.1)— A is sequenced before D, or
    (12.2)— A synchronizes with D, and both A and D are sequentially
    consistent atomic operations (31.4), or
    (12.3)— there are evaluations B and C such that A is sequenced before B,
    B simply happens before C, and C is sequenced before D, or
    (12.4)— there is an evaluation B such that A strongly happens before B,
    and B strongly happens before D.
    [Note: Informally, if A strongly happens before B, then A appears to be evaluated before B in all contexts. Strongly happens before excludes
    consume operations. — end note]"

    The first occurrence of "strongly happens before" in that clause is also italicized.

    Note that "A is sequenced before D" would be sufficient to ensure that
    both "A happens before D" and "A strongly happens before D" are true.
    The difference between the two terms only shows up if A is not sequenced
    before D. In that case, at a minimum you must have "A inter-thread
    happens before D", but is not synchronized with D.

    For instance A inter-thread happens before D if it is dependency-ordered
    before D. (6.9.2.1p9). This could happen if A performs a release
    operation on an atomic object M , and, in another thread, D performs a
    consume operation on M and reads the value written by A (6.9.2.1p8).

    In that case, the requirements associated with "A happens before D" must
    be met, but those associated with "A strongly happens before D" need not be.

    Do you need an explanation of the parts of the above explanation that
    use the terms "release" and "consume"? I have little experience with multi-threaded code - someone else might be able to explain those better
    than I can.




    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From James Kuyper@3:633/280.2 to All on Wed Apr 2 05:37:50 2025
    On 4/1/25 06:20, Michael S wrote:
    ....
    It seems to me that saying that events are "strongly ordered" makes
    sense only when "weakly ordered" and "unordered" are not the same.
    In this particular case I don't see how exactly "weakly ordered"
    differs from "unordered".

    The term is "happens before", not "ordered". The standard defines
    neither "weakly happens before" nor anything connected to "happens
    before" that would be analogous to "unordered". See my response
    else-thread for more details on the relevant definitions.


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From James Kuyper@3:633/280.2 to All on Wed Apr 2 05:37:50 2025
    On 4/1/25 06:20, Michael S wrote:
    ....
    It seems to me that saying that events are "strongly ordered" makes
    sense only when "weakly ordered" and "unordered" are not the same.
    In this particular case I don't see how exactly "weakly ordered"
    differs from "unordered".

    The term is "happens before", not "ordered". The standard defines
    neither "weakly happens before" nor anything connected to "happens
    before" that would be analogous to "unordered". See my response
    else-thread for more details on the relevant definitions.


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Wed Apr 2 06:39:07 2025
    On 4/1/2025 11:32 AM, James Kuyper wrote:
    On 01.04.2025 10:26, Muttley@DastardlyHQ.org wrote:
    On Mon, 31 Mar 2025 19:42:48 -0400
    James Kuyper <jameskuyper@alumni.caltech.edu> wibbled:
    On 31.03.2025 17:01, Muttley@DastardlyHQ.org wrote:
    On Mon, 31 Mar 2025 15:39:53 +0300
    Paavo Helde <eesnimi@osa.pri.ee> wibbled:
    On 31.03.2025 12:09, Muttley@DastardlyHQ.org wrote:
    "If [initialization] is deferred, it strongly happens before any
    non-initialization odr-use of any non-inline function or non-inline
    variable defined in the same translation unit as the variable to be
    initialized."

    Who writes this stuff? Its borderline gibberish.

    Keep in mind that the key thing that makes this seem like gibberish is
    the use of precisely defined technical jargon, which is used for the
    same reason that jargon is used in many other contexts: it has a more
    precisely specified meaning than more informal wording would have had.

    Key pieces of jargon: "strongly happens before", "non-initialization",

    "strongly happens before" is genuine gibberish. Either something happens before
    or it doesn't, the adverb is entirely superfluous.

    Terms are explicitly defined by the C++ standard precisely because their meaning cannot be inferred by using ordinary English to interpret the
    words that make them up. Both "happens before" and "strongly happens
    before" are separate pieces of C++ jargon, and the requirements for qualifying as "strongly happens before" are in fact stronger than those
    for "happens before".

    "An evaluation A happens before an evaluation B (or, equivalently, B
    happens after A) if:
    (10.1)— A is sequenced before B, or
    (10.2)— A inter-thread happens before B.
    The implementation shall ensure that no program execution demonstrates a cycle in the “happens before” relation. [Note: This cycle would
    otherwise be possible only through the use of consume operations. — end note]" (6.9.2.1p10).

    the first occurrence of "happens before" in that clause is in italics,
    an ISO convention indicating that it is a piece of specialized jargon
    whose definition is provided by the sentence in which it occurs. Note
    that "sequenced before" and "inter-thread happens before" are two other pieces of standard-defined jargon.

    "An evaluation A strongly happens before an evaluation D if, either
    (12.1)— A is sequenced before D, or
    (12.2)— A synchronizes with D, and both A and D are sequentially
    consistent atomic operations (31.4), or
    (12.3)— there are evaluations B and C such that A is sequenced before B,
    B simply happens before C, and C is sequenced before D, or
    (12.4)— there is an evaluation B such that A strongly happens before B,
    and B strongly happens before D.
    [Note: Informally, if A strongly happens before B, then A appears to be evaluated before B in all contexts. Strongly happens before excludes
    consume operations. — end note]"

    The first occurrence of "strongly happens before" in that clause is also italicized.

    Note that "A is sequenced before D" would be sufficient to ensure that
    both "A happens before D" and "A strongly happens before D" are true.
    The difference between the two terms only shows up if A is not sequenced before D. In that case, at a minimum you must have "A inter-thread
    happens before D", but is not synchronized with D.

    For instance A inter-thread happens before D if it is dependency-ordered before D. (6.9.2.1p9). This could happen if A performs a release
    operation on an atomic object M , and, in another thread, D performs a consume operation on M and reads the value written by A (6.9.2.1p8).

    In that case, the requirements associated with "A happens before D" must
    be met, but those associated with "A strongly happens before D" need not be.

    Do you need an explanation of the parts of the above explanation that
    use the terms "release" and "consume"? I have little experience with multi-threaded code - someone else might be able to explain those better
    than I can.

    Consume is weaker than acquire. It is basically used for data-dependent
    loads. For instance, it can be used for RCU algorithms that do not need
    a full acquire barrier. Now, iirc, the only system that actually needs
    an explicit barrier for data-dependent loads is the dec alpha. Actually,
    it kind of seems like consume was meant for RCU like algos.

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Michael S@3:633/280.2 to All on Wed Apr 2 07:10:40 2025
    On Tue, 1 Apr 2025 13:55:43 -0400
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    On 4/1/25 00:29, Jakob Bohm wrote:


    However treating the standard text as an imperfect description of traditional compiler techniques used for 2nd. Edition compilers
    makes much more sense .

    No, that does not. The standard was never intended as a description of
    how compilers actually work, it was always intended to be a
    description of requirements on how they should work.


    It sounds to me like a revisionisms.
    Most language standards are intended to codify commonalities of work of existing compilers. That applies to C++98 and mostly, although not
    completely, to the following C++ standards.
    There exist exceptions, for example, Ada83. But they are exceptions.






    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Michael S@3:633/280.2 to All on Wed Apr 2 07:26:00 2025
    On Tue, 1 Apr 2025 14:32:54 -0400
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    On 01.04.2025 10:26, Muttley@DastardlyHQ.org wrote:
    On Mon, 31 Mar 2025 19:42:48 -0400
    James Kuyper <jameskuyper@alumni.caltech.edu> wibbled: =20
    On 31.03.2025 17:01, Muttley@DastardlyHQ.org wrote: =20
    On Mon, 31 Mar 2025 15:39:53 +0300
    Paavo Helde <eesnimi@osa.pri.ee> wibbled: =20
    On 31.03.2025 12:09, Muttley@DastardlyHQ.org wrote:
    "If [initialization] is deferred, it strongly happens before any
    non-initialization odr-use of any non-inline function or
    non-inline variable defined in the same translation unit as the
    variable to be initialized." =20

    Who writes this stuff? Its borderline gibberish. =20

    Keep in mind that the key thing that makes this seem like
    gibberish is the use of precisely defined technical jargon, which
    is used for the same reason that jargon is used in many other
    contexts: it has a more precisely specified meaning than more
    informal wording would have had.

    Key pieces of jargon: "strongly happens before",
    "non-initialization", =20
    =20
    "strongly happens before" is genuine gibberish. Either something
    happens before or it doesn't, the adverb is entirely superfluous. =20
    =20
    Terms are explicitly defined by the C++ standard precisely because
    their meaning cannot be inferred by using ordinary English to
    interpret the words that make them up. Both "happens before" and
    "strongly happens before" are separate pieces of C++ jargon, and the requirements for qualifying as "strongly happens before" are in fact
    stronger than those for "happens before".
    =20
    "An evaluation A happens before an evaluation B (or, equivalently, B
    happens after A) if:
    (10.1)=E2=80=94 A is sequenced before B, or
    (10.2)=E2=80=94 A inter-thread happens before B.
    The implementation shall ensure that no program execution
    demonstrates a cycle in the =E2=80=9Chappens before=E2=80=9D relation. [N=
    ote: This
    cycle would otherwise be possible only through the use of consume
    operations. =E2=80=94 end note]" (6.9.2.1p10).
    =20
    the first occurrence of "happens before" in that clause is in italics,
    an ISO convention indicating that it is a piece of specialized jargon
    whose definition is provided by the sentence in which it occurs. Note
    that "sequenced before" and "inter-thread happens before" are two
    other pieces of standard-defined jargon.
    =20
    "An evaluation A strongly happens before an evaluation D if, either (12.1)=E2=80=94 A is sequenced before D, or
    (12.2)=E2=80=94 A synchronizes with D, and both A and D are sequentially consistent atomic operations (31.4), or
    (12.3)=E2=80=94 there are evaluations B and C such that A is sequenced be=
    fore
    B, B simply happens before C, and C is sequenced before D, or
    (12.4)=E2=80=94 there is an evaluation B such that A strongly happens bef=
    ore
    B, and B strongly happens before D.
    [Note: Informally, if A strongly happens before B, then A appears to
    be evaluated before B in all contexts. Strongly happens before
    excludes consume operations. =E2=80=94 end note]"
    =20
    The first occurrence of "strongly happens before" in that clause is
    also italicized.
    =20
    Note that "A is sequenced before D" would be sufficient to ensure that
    both "A happens before D" and "A strongly happens before D" are true.
    The difference between the two terms only shows up if A is not
    sequenced before D. In that case, at a minimum you must have "A
    inter-thread happens before D", but is not synchronized with D.
    =20
    For instance A inter-thread happens before D if it is
    dependency-ordered before D. (6.9.2.1p9). This could happen if A
    performs a release operation on an atomic object M , and, in another
    thread, D performs a consume operation on M and reads the value
    written by A (6.9.2.1p8).
    =20
    In that case, the requirements associated with "A happens before D"
    must be met, but those associated with "A strongly happens before D"
    need not be.
    =20

    You probably paid attentions that the text is not crystal clear.
    It looks like authors of the Standard invent their own terminology not
    only when absolutely necessary but sometimes even when there exist
    established terms for the same things. To their defense, I could say
    that in the branch of CS that is related to concurrency and parallelism
    very few terms are 100% consensus.

    Do you need an explanation of the parts of the above explanation that
    use the terms "release" and "consume"? I have little experience with multi-threaded code - someone else might be able to explain those
    better than I can.
    =20

    I suspected that the difference between "strong happens before" and
    "happens before" is somehow related to implied ordering due to
    causality. After reading the text above my feeling changed from
    suspicion to strong suspicion. But it is not yet a certainty.







    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Keith Thompson@3:633/280.2 to All on Wed Apr 2 08:20:49 2025
    Michael S <already5chosen@yahoo.com> writes:
    On Tue, 1 Apr 2025 13:55:43 -0400
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:
    On 4/1/25 00:29, Jakob Bohm wrote:
    However treating the standard text as an imperfect description of
    traditional compiler techniques used for 2nd. Edition compilers
    makes much more sense .

    No, that does not. The standard was never intended as a description of
    how compilers actually work, it was always intended to be a
    description of requirements on how they should work.

    It sounds to me like a revisionisms.
    Most language standards are intended to codify commonalities of work of existing compilers. That applies to C++98 and mostly, although not completely, to the following C++ standards.

    I disagree. Many language standards are *based on* the behavior
    of existing compilers. In the case of C, for example, there were
    multiple implementations before the first standard was published, and
    the standard was largely based on their behavior (and on K&R1). The
    C++ standard evolved similarly; there were several implementations
    and books before the first C++ standard was published.

    But once a standard is published, it is a set of requirements on
    conforming implementations and programs. Note in particular that
    standards typically don't mention any specific implementations,
    and that implementations have had to be changed to satisfy the
    standard's requirements.

    I think of a language standard as a proposed contract between
    implementers and programmers. If an implementation claims
    conformance, programmers have a right to expect conforming code to
    behave as specified by the standard. But neither implementers nor
    programmers are necessarily required to accept the contract.

    There exist exceptions, for example, Ada83. But they are exceptions.

    Ada 83 was unusual in the sense that the standard was deliberately
    developed first, and implementations followed (though a lot of it
    was based on other existing languages). But once published, the
    Ada standard served much the same purpose as the C and C++ standards.

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: None to speak of (3:633/280.2@fidonet)
  • From James Kuyper@3:633/280.2 to All on Wed Apr 2 09:57:28 2025
    On 4/1/25 16:10, Michael S wrote:
    On Tue, 1 Apr 2025 13:55:43 -0400
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:
    ....
    No, that does not. The standard was never intended as a description of
    how compilers actually work, it was always intended to be a
    description of requirements on how they should work.


    It sounds to me like a revisionisms.
    Most language standards are intended to codify commonalities of work of existing compilers. That applies to C++98 and mostly, although not completely, to the following C++ standards.

    Regardless of whether they codify existing implementations or innovate
    far beyond them, programming language standards are codifications - and
    that makes them prescriptive documents. The C++ standard exists to
    define what it means to be a conforming implementation of C++, and what
    it means to write well-formed code. Well-formed code translated by a
    conforming implementation of C++ will produce the behavior that meets
    the requirements specified by the standard - and that's the point of the standard.

    However, C++98 was in fact notorious for the extent to which it went
    beyond merely codifying existing practice. In particular, <iostream> was
    a big change from <iostream.h>, and the process of incorporating STL
    into the C++ standard library involved a lot of changes.
    And every revision to the C++ standard has increased C++'s reputation
    for innovating well beyond existing practice. The language defined by
    the latest standard is very different from the one defined by C++98.

    The other standard that I'm most familiar with, the C standard, is by comparison a very slowly changing standard - but C90, C99, and C2011
    were all pretty significant changes from existing practice.

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From James Kuyper@3:633/280.2 to All on Wed Apr 2 10:08:09 2025
    On 4/1/25 16:26, Michael S wrote:
    ....
    You probably paid attentions that the text is not crystal clear.
    It looks like authors of the Standard invent their own terminology not
    only when absolutely necessary but sometimes even when there exist established terms for the same things. To their defense, I could say
    that in the branch of CS that is related to concurrency and parallelism
    very few terms are 100% consensus.

    Feel free to propose alternative wording with the same precise meaning.
    Keep in mind that these terms were invented to convey a more
    precisely-define meaning than existing terms would have provided, so
    wording that says "approximately" the same thing would not be an
    acceptable replacement.

    ....
    I suspected that the difference between "strong happens before" and
    "happens before" is somehow related to implied ordering due to
    causality. After reading the text above my feeling changed from
    suspicion to strong suspicion. But it is not yet a certainty.

    I'm no expert in multi-threaded code, so I don't fully understand the significance of what it says. However, I able to derive the fact that
    there is a difference between the two terms only when one evaluation "inter-thread happens before" another evaluation, and the two
    evaluations are not synchronized. In other words, the difference is with
    regard to what's required for unsynchronized threads.


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From James Kuyper@3:633/280.2 to All on Wed Apr 2 13:55:56 2025
    On 4/1/25 14:32, James Kuyper wrote:
    ....
    Note that "A is sequenced before D" would be sufficient to ensure that
    both "A happens before D" and "A strongly happens before D" are true.
    The difference between the two terms only shows up if A is not sequenced before D. In that case, at a minimum you must have "A inter-thread
    happens before D", but is not synchronized with D.

    For instance A inter-thread happens before D if it is dependency-ordered before D. (6.9.2.1p9). This could happen if A performs a release
    operation on an atomic object M , and, in another thread, D performs a consume operation on M and reads the value written by A (6.9.2.1p8).

    I got sidetracked by life before I could look into that further, but
    I've traced down relevant text in 1.10p7: "An evaluation A that performs
    a release operation on an object M synchronizes with an evaluation B
    that performs an acquire operation on M and reads a value written by any
    side effect in the release sequence headed by A."

    Therefore, A "happens before" D, but does not "strongly happen before" D
    if A does a release on M, and D does a consume on M, but D does not do
    an acquire on M followed by reading a value written by a side effect of
    A's release sequence.

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Muttley@DastardlyHQ.org@3:633/280.2 to All on Wed Apr 2 18:34:52 2025
    On Tue, 1 Apr 2025 14:32:54 -0400
    James Kuyper <jameskuyper@alumni.caltech.edu> wibbled:
    "An evaluation A strongly happens before an evaluation D if, either
    :
    (12.4)— there is an evaluation B such that A strongly happens before B,
    and B strongly happens before D.

    Looks like a circular definition to me. But regardless, looks like the usual unintelligable nonsense thats no use to anyone except the people who wrote it.

    Do you need an explanation of the parts of the above explanation that
    use the terms "release" and "consume"? I have little experience with >multi-threaded code - someone else might be able to explain those better
    than I can.

    I don't particularly care. I generally find standards and RFCs unreadable.
    Its often easier to look at code or test with a working example to see what actually happens. Thats the method I used to write my NNTP and NMAP clients amongst many others.


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From David Brown@3:633/280.2 to All on Wed Apr 2 19:29:17 2025
    On 01/04/2025 22:10, Michael S wrote:
    On Tue, 1 Apr 2025 13:55:43 -0400
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    On 4/1/25 00:29, Jakob Bohm wrote:


    However treating the standard text as an imperfect description of
    traditional compiler techniques used for 2nd. Edition compilers
    makes much more sense .

    No, that does not. The standard was never intended as a description of
    how compilers actually work, it was always intended to be a
    description of requirements on how they should work.


    It sounds to me like a revisionisms.
    Most language standards are intended to codify commonalities of work of existing compilers. That applies to C++98 and mostly, although not completely, to the following C++ standards.
    There exist exceptions, for example, Ada83. But they are exceptions.


    Most language standards /started/ with a codification of existing tools.
    Making a language standard is a lot of effort, and is rarely done
    until there is at least one implementation and it has been used for a
    while - there's little point spending a lot of time defining a language
    that might never be used, or might turn out to be impractical or
    inefficient to implement. Initial standards are often books - K&R "The
    C Programming Language" and Stroustrup "The C++ Programming Language"
    being fine examples. More official standards can come later.

    Sometimes there is a "reference implementation" and the documentation
    for that becomes, in effect, the standard.

    But once the process is in place, it is now the standard that defines
    the language, and future implementations are intended to conform to the standard. Implementations can have extensions and extra features, and
    those can strongly influence future versions of the standard, but the
    standard defines how the language works.

    Thus many features that were added to C and C++ after their initial standardisation began as extensions in compilers - especially gcc. But
    the standardised features were what the language committees felt were
    best for the language going forward - /not/ a codification of existing practice. There are countless examples of new features in language
    standards that are clearly inspired by, but noticeably different from, extensions in compilers.



    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)