• Re: thread_local question...

    From Andrey Tarasevich@21:1/5 to Chris M. Thomasson on Wed Oct 9 19:33:55 2024
    On 10/09/24 7:02 PM, Chris M. Thomasson wrote:

    void
    ct_thread(
        ct_shared& shared,
        unsigned long id
    ) {
        // Well, self should be per thread...
        thread_local ct_per_thread self(shared, id);

        ct_foo();
    }


    Um... Declaring a `thread_local` variable in block scope can serve only
    one purpose: to _hide_ the variable, to prevent anyone else from
    accessing it directly. `thread_local` is somewhat similar to `static` in single-threaded applications: the variable retains its value even when
    you exit and re-enter the scope. In all other respects the variable
    itself remain invisible to the outside scopes, which is the whole
    purpose of declaring it in block scope.

    This is exactly what you did: you declared a variable as `thread_local`
    in block scope. Which means it will retain its value when you exit and
    re-enter the scope, but (as opposed to `static`) it is going to be a
    per-thread variable. Since you declared it locally, it implies that you _wanted_ to make it inaccessible from other scopes. Why are asking "how
    to get at self?" then?

    The only way to access such variable from other scopes is to access it indirectly: through a reference/pointer that you create in advance
    (where the variable is visible) and then somehow hand that
    reference/pointer over to other scopes. If you don't what to fiddle with indirect access, then declare your variable as `thread_local` in
    namespace scope. That way you will easily be able to get at it from
    other functions.

    However, the real question here is: why you are even declaring your
    variable as `thread_local`? A regular local variable inside a thread
    function is already as "thread local" as it can possibly get. The only
    thing that `thread_local` will give you is the retention of the old
    value between calls. Do you really need that?

    --
    Best regards,
    Andrey

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Andrey Tarasevich@21:1/5 to Andrey Tarasevich on Wed Oct 9 19:40:55 2024
    On 10/09/24 7:33 PM, Andrey Tarasevich wrote:
    On 10/09/24 7:02 PM, Chris M. Thomasson wrote:

    void
    ct_thread(
         ct_shared& shared,
         unsigned long id
    ) {
         // Well, self should be per thread...
         thread_local ct_per_thread self(shared, id);

         ct_foo();
    }



    However, the real question here is: why you are even declaring your
    variable as `thread_local`? A regular local variable inside a thread
    function is already as "thread local" as it can possibly get. The only
    thing that `thread_local` will give you is the retention of the old
    value between calls. Do you really need that?


    An additional remark:

    The "retention of the old value between calls" would apply if you
    declared a variable like that in some nested function invoked multiple
    times from the top-level thread function.

    But in your example the variable is declared in the top-level thread
    function itself. In that case there will be no "retention of the old
    value between calls" simply because once the thread function ends, the
    thread ends as well, and all its `thread_local` variables die anyway.
    So, your declaration does not seem to make any practical sense.

    --
    Best regards,
    Andrey

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From jseigh@21:1/5 to Chris M. Thomasson on Thu Oct 10 07:52:53 2024
    On 10/9/24 22:02, Chris M. Thomasson wrote:
    How can I get access to self in my ct_foo() function below? Am I
    misusing thread_local here? I want self to be able to be accessible from
    any function that my ct_thread() function calls. It feels like I am
    doing something wrong here. However, I am getting correct ctor's and
    dtor's, I am not sure how to access self from ct_foo() called from ct_thread()?


    std::thread::id id = std::this_thread::get_id();

    C tss uses a thread local array I think but I don't know
    it gets notification on individual thread exits so it
    can run the dtor. C++ has a cvar notify all on thread
    exits.

    I have a different hack which I won't get around to
    until I need it.

    Joe Seigh

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From jseigh@21:1/5 to Chris M. Thomasson on Thu Oct 10 15:57:42 2024
    On 10/10/24 15:04, Chris M. Thomasson wrote:
    On 10/10/2024 4:52 AM, jseigh wrote:
    On 10/9/24 22:02, Chris M. Thomasson wrote:
    How can I get access to self in my ct_foo() function below? Am I
    misusing thread_local here? I want self to be able to be accessible
    from any function that my ct_thread() function calls. It feels like I
    am doing something wrong here. However, I am getting correct ctor's
    and dtor's, I am not sure how to access self from ct_foo() called
    from ct_thread()?


    std::thread::id id = std::this_thread::get_id();

    C tss uses a thread local array I think but I don't know
    it gets notification on individual thread exits so it
    can run the dtor.  C++ has a cvar notify all on thread
    exits.

    I have a different hack which I won't get around to
    until I need it.

    I still don't know how C++ calls dtors wrt per-thread objects via thread_local. My hack would be to use tss_create and be done with it.


    I got some stack traces from C vs C++ threads (not the main threads
    which have identical stack traces).

    C
    #4 0x00000000004011c6 in test ()
    #5 0x00007ff68a489be1 in start_thread (arg=<optimized out>) at pthread_create.c:440
    #6 0x00007ff68a50ed40 in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81

    C++
    #4 0x00000000004012b6 in test(void*) ()
    #5 0x00007fa23f4dbad4 in std::execute_native_thread_routine
    (__p=0x173ceb0) at ../../../../../libstdc++-v3/src/c++11/thread.cc:82
    #6 0x00007fa23f089d22 in start_thread (arg=<optimized out>) at pthread_create.c:443
    #7 0x00007fa23f10ed40 in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81

    So the tss uses the pthread stuff and C++ uses std::execute_native_thread_routine on top of that.

    C and C++ main
    #4 0x0000000000401056 in main ()
    #5 0x00007fae98e295d0 in __libc_start_call_main
    (main=main@entry=0x401050 <main>, argc=argc@entry=1,
    argv=argv@entry=0x7ffff84f1d18) at ../sysdeps/nptl/libc_start_call_main.h:58
    #6 0x00007fae98e29680 in __libc_start_main_impl (main=0x401050 <main>,
    argc=1, argv=0x7ffff84f1d18, init=<optimized out>,
    fini=<optimized out>, rtld_fini=<optimized out>,
    stack_end=0x7ffff84f1d08) at ../csu/libc-start.c:389
    #7 0x0000000000401085 in _start ()

    No extra c++ magic sauce there that I can see.

    I wonder how many people realize a thread's entry point isn't
    necessarily the first thing that's called.

    Joe Seigh

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From jseigh@21:1/5 to Chris M. Thomasson on Fri Oct 11 09:50:13 2024
    On 10/10/24 15:04, Chris M. Thomasson wrote:
    On 10/10/2024 4:52 AM, jseigh wrote:
    On 10/9/24 22:02, Chris M. Thomasson wrote:
    How can I get access to self in my ct_foo() function below? Am I
    misusing thread_local here? I want self to be able to be accessible
    from any function that my ct_thread() function calls. It feels like I
    am doing something wrong here. However, I am getting correct ctor's
    and dtor's, I am not sure how to access self from ct_foo() called
    from ct_thread()?


    std::thread::id id = std::this_thread::get_id();

    C tss uses a thread local array I think but I don't know
    it gets notification on individual thread exits so it
    can run the dtor.  C++ has a cvar notify all on thread
    exits.

    I have a different hack which I won't get around to
    until I need it.

    I still don't know how C++ calls dtors wrt per-thread objects via thread_local. My hack would be to use tss_create and be done with it.


    Ok, it looks like they are using libc atexit function (stdlib.h) to
    invoke tls cleanup on thread exit.

    Joe Seigh

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From jseigh@21:1/5 to jseigh on Fri Oct 11 17:05:33 2024
    On 10/11/24 09:50, jseigh wrote:
    On 10/10/24 15:04, Chris M. Thomasson wrote:
    On 10/10/2024 4:52 AM, jseigh wrote:
    On 10/9/24 22:02, Chris M. Thomasson wrote:
    How can I get access to self in my ct_foo() function below? Am I
    misusing thread_local here? I want self to be able to be accessible
    from any function that my ct_thread() function calls. It feels like
    I am doing something wrong here. However, I am getting correct
    ctor's and dtor's, I am not sure how to access self from ct_foo()
    called from ct_thread()?


    std::thread::id id = std::this_thread::get_id();

    C tss uses a thread local array I think but I don't know
    it gets notification on individual thread exits so it
    can run the dtor.  C++ has a cvar notify all on thread
    exits.

    I have a different hack which I won't get around to
    until I need it.

    I still don't know how C++ calls dtors wrt per-thread objects via
    thread_local. My hack would be to use tss_create and be done with it.


    Ok, it looks like they are using libc atexit function (stdlib.h) to
    invoke tls cleanup on thread exit.

    Correction. atexit is for process exit not thread exit. So those
    start_ functions are where they are doing the exit handling.

    Joe Seigh

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)