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()?
I must be missing something obvious.
First of all can you compile and run it?
_______________________________
Still, I think the tss_create() is better. Perhaps because it's more in
line with PThreads... ;^)
Any thoughts?
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();
}
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?
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.
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.[...]
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()?
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.
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()?
That's why thread in libwy (RAII) is implemented as a class, 'thread' is an overloadstd::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.
However, this "works", but the only reason the dtor is being called has nothing to do with thread_local. I resorted to using thread_local for a pointer to a local per_thread object on the threads stack. It's dtorYes, RRAD is a problem of multi-threaded program.
means the thread exited. However, this is a lot different than
tss_create or pthread_key_create. Iirc, those dtors get called a lot
deeper in thread shutdown.
_______________________
thread_local ct_per_thread* g_per_thread = nullptr;
void
ct_foo()
{
// Okay, what about this shit!
{
std::unique_lock<std::mutex> lock(g_per_thread->m_shared.m_cout_lock);
std::cout << "ct_foo(" << g_per_thread->m_id << ")" << std::endl;
}
}
void
ct_thread(
ct_shared& shared,
unsigned long id
) {
ct_per_thread self(shared, id);
g_per_thread = &self;
ct_foo();
}
_______________________
I guess that is a hack.--- Synchronet 3.20a-Linux NewsLink 1.114
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.
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.
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.
[...]On 10/10/24 15:04, Chris M. Thomasson wrote:
I wonder how many people realize a thread's entry point isn't
necessarily the first thing that's called.
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.
On 10/11/2024 6:50 AM, 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.
Thanks for all of the info Joe! I have an idea that might allow me to
get a dtor called from thread_local in my test code. I just need to try
it. Wrt:
_________________________________
thread_local ct_per_thread* g_per_thread = nullptr;
void
ct_foo()
{
// Okay, what about this shit!
{
std::unique_lock<std::mutex> lock(g_per_thread-
m_shared.m_cout_lock);std::cout << "ct_foo(" << g_per_thread->m_id << ")" << std::endl;
}
}
void
ct_thread(
ct_shared& shared,
unsigned long id
) {
ct_per_thread self(shared, id);
g_per_thread = &self;
ct_foo();
}
_________________________________
Well, what if I made self in ct_thread thread_local as well? That should call self's dtor deeper down the pipe, so to speak. Humm... It should
work fine. Then any function that ct_thread calls would be able to
access self via g_per_thread...
;^)
Humm... It would still not be "dynamic" like the pthread and/or
tss_create version.
[...][...]
Check this out... Does it work for you? The ct_per_thread dtors should
be getting called deeper in thread shutdown...
~ct_per_thread()
{
{
std::unique_lock<std::mutex> lock(m_shared.m_cout_lock);
std::cout << "ct_per_thread::~ct_per_thread(" << m_id <<
")" << std::endl;
}
}
};[...]
ct_plot_pre_alpha.exe!ct_per_thread::~ct_per_thread() Line 39 C++ct_plot_pre_alpha.exe!`ct_thread'::`3'::`dynamic atexit destructor
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.
ct_plot_pre_alpha.exe!ct_per_thread::~ct_per_thread() Line 39 C++ct_plot_pre_alpha.exe!`ct_thread'::`3'::`dynamic atexit destructor
On 10/11/2024 2:05 PM, jseigh wrote:
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.
Well, here is a call stack for my most recent try wrt tss dtors in pure
C++:
ct_plot_pre_alpha.exe!ct_per_thread::~ct_per_thread() Line 39 C++ct_plot_pre_alpha.exe!`ct_thread'::`3'::`dynamic atexit destructor for 'self''() C++
ct_plot_pre_alpha.exe!__dyn_tls_dtor(void * __formal, const unsigned long dwReason, void * __formal) Line 122 C++
ntdll.dll!00007ffbed20bfca() Unknown
ntdll.dll!00007ffbed1b8b5f() Unknown
ntdll.dll!00007ffbed1b97e9() Unknown
ntdll.dll!00007ffbed1b9428() Unknown
ntdll.dll!00007ffbed1eaf7e() Unknown
KernelBase.dll!00007ffbea68e1ca() Unknown
ucrtbased.dll!00007ffb83e932cb() Unknown
ucrtbased.dll!00007ffb83e93931() Unknown
ucrtbased.dll!00007ffb83e93017() Unknown
kernel32.dll!00007ffbec15257d() Unknown
ntdll.dll!00007ffbed1eaf08() Unknown
atexit is in there.
On 10/10/2024 12:20 PM, wij wrote:
[...]
Check this shit out:
Here is my crude code:
_______________________________________
#include <iostream>
#include <functional>
#include <thread>
#include <atomic>
#include <mutex>
#define CT_THREADS 5
struct ct_shared
{
std::mutex m_cout_lock;
};
struct ct_per_thread
{
ct_shared& m_shared;
unsigned long m_id;
ct_per_thread(
ct_shared& shared,
unsigned long id
): m_shared(shared),
m_id(id)
{
{
std::unique_lock<std::mutex> lock(m_shared.m_cout_lock);
std::cout << "ct_per_thread::ct_per_thread(" << m_id << ")"
<< std::endl;
}
}
~ct_per_thread()
{
{
std::unique_lock<std::mutex> lock(m_shared.m_cout_lock);
std::cout << "ct_per_thread::~ct_per_thread(" << m_id <<
")" << std::endl;
}
}
};
thread_local ct_per_thread* g_per_thread = nullptr;
void
ct_foo()
{
// Okay, what about this shit!
{
std::unique_lock<std::mutex> lock(g_per_thread->m_shared.m_cout_lock);
std::cout << "ct_foo(" << g_per_thread->m_id << ")" << std::endl;
}
}
void
ct_thread(
ct_shared& shared,
unsigned long id
) {
{
thread_local ct_per_thread self(shared, id);
g_per_thread = &self;
}
ct_foo();
}
intDon't know what the program is demonstrating.
main()
{
std::cout << "ct_plot_pre_alpha... Testing 123! :^)\n\n";
std::cout << "_____________________________________________" << std::endl;
{
ct_shared shared;
{
std::thread threads[CT_THREADS];
std::cout << "launching " << CT_THREADS << " threads..." <<
std::endl;
for (unsigned long i = 0; i < CT_THREADS; ++i) {
threads[i] = std::thread(ct_thread, std::ref(shared), i);
}
for (unsigned long i = 0; i < CT_THREADS; ++i) {
threads[i].join();
}
}
}
std::cout << "_____________________________________________\n"; std::cout << "complete!\n";
return 0;
}
_______________________________________
On Sun, 2024-10-20 at 19:12 -0700, Chris M. Thomasson wrote:
On 10/10/2024 12:20 PM, wij wrote:
[...]
Check this shit out:
Here is my crude code:
_______________________________________
#include <iostream>
#include <functional>
#include <thread>
#include <atomic>
#include <mutex>
#define CT_THREADS 5
struct ct_shared
{
std::mutex m_cout_lock;
};
struct ct_per_thread
{
ct_shared& m_shared;
unsigned long m_id;
ct_per_thread(
ct_shared& shared,
unsigned long id
): m_shared(shared),
m_id(id)
{
{
std::unique_lock<std::mutex> lock(m_shared.m_cout_lock);
std::cout << "ct_per_thread::ct_per_thread(" << m_id << ")"
<< std::endl;
}
}
~ct_per_thread()
{
{
std::unique_lock<std::mutex> lock(m_shared.m_cout_lock);
std::cout << "ct_per_thread::~ct_per_thread(" << m_id <<
")" << std::endl;
}
}
};
thread_local ct_per_thread* g_per_thread = nullptr;
void
ct_foo()
{
// Okay, what about this shit!
{
std::unique_lock<std::mutex> lock(g_per_thread->m_shared.m_cout_lock);
std::cout << "ct_foo(" << g_per_thread->m_id << ")" << std::endl;
}
}
void
ct_thread(
ct_shared& shared,
unsigned long id
) {
{
thread_local ct_per_thread self(shared, id);
g_per_thread = &self;
}
ct_foo();
}
int
main()
{
std::cout << "ct_plot_pre_alpha... Testing 123! :^)\n\n";
std::cout << "_____________________________________________" << std::endl;
{
ct_shared shared;
{
std::thread threads[CT_THREADS];
std::cout << "launching " << CT_THREADS << " threads..." <<
std::endl;
for (unsigned long i = 0; i < CT_THREADS; ++i) {
threads[i] = std::thread(ct_thread, std::ref(shared), i);
}
for (unsigned long i = 0; i < CT_THREADS; ++i) {
threads[i].join(); }
}
}
std::cout << "_____________________________________________\n"; std::cout << "complete!\n";
return 0;
}
_______________________________________
Don't know what the program is demonstrating.
The following is what I thought what ct_thread is doing.
1. In libwy, each thread is represented by a PThread object, following the RAII
principle. (your program looked to me std::thread API has no idea of RAII).
2. libwy only has Mutex (wrapper of pthread_mutex), because other kinds of mutexes are considered not often used and easily implemented (except futex)
and many application variations, i.e. read/write mutex.
3. Wy::PThread has no public facilities for 'thread specific' (thread local),
because in most cases, 'thread local' can be implemented as class data member.
(Wy::PThread is old from the time the underlying Linux Thread is buggy, and I am tired to revise it without real cases showing the necessarity.)
// t.cpp
#include <Wy.pthread.h>
#include <Wy.stdio.h>
using namespace Wy;
class Thread : public PThread {
Mutex *m_gmtx; // for 'thread common' data
int m_id;
// Many 'thread local' data can be put here.
public:
Thread(Mutex& mtx, int id) : m_gmtx(&mtx), m_id(id) {};
Errno begin() override { return PThread::begin(); };
~Thread() {
NoCancel noc;
tmain_close(); // Stop possibly active thread, then destruction begins.
cout << "~Thread(mtx," << m_id << ")" WY_ENDL;
};
protected:
Errno tmain() override {
Mutex::Lock aa(*m_gmtx);
cout << "Thread(mtx," << m_id << ")" WY_ENDL;
return Ok;
};
};
#define CT_THREADS 5
int main()
try {
Errno r;
Mutex shared_mutex;
Thread thrd[CT_THREADS]={
Thread(shared_mutex,0), Thread(shared_mutex,1), Thread(shared_mutex,2), Thread(shared_mutex,3), Thread(shared_mutex,4), };
for(int i=0; i<CT_THREADS; ++i) {
if((r=thrd[i].begin())!=Ok) {
WY_THROW(r);
}
}
for(int i=0; i<CT_THREADS; ++i) {
if((r=thrd[i].wait_if(PThread::Running))!=Ok) {
WY_THROW(r);
}
}
return 0;
}
catch(const Errno& e) {
cerr << wrd(e) << WY_ENDL;
throw;
}
catch(...) {
cerr << "Unknown thrown object" WY_ENDL;
throw;
};
-----------------------------
[]$ g++ t.cpp -lwy
[]$ ./a.out
Thread(mtx,0)
Thread(mtx,1)
Thread(mtx,4)
Thread(mtx,2)
Thread(mtx,3)
~Thread(mtx,4)
~Thread(mtx,3)
~Thread(mtx,2)
~Thread(mtx,1)
~Thread(mtx,0)
Sysop: | DaiTengu |
---|---|
Location: | Appleton, WI |
Users: | 991 |
Nodes: | 10 (1 / 9) |
Uptime: | 75:29:39 |
Calls: | 12,948 |
Calls today: | 2 |
Files: | 186,574 |
Messages: | 3,264,524 |