是否有异步安全的方法来获取Linux中的当前线程ID?

Bee*_*ope 5 linux gcc posix signals pthreads

有没有办法从Linux中的信号处理程序获取当前线程ID?该getpid()方法可以满足我的需求,但目前尚不清楚它是否是异步安全的.man 7 signal提供了一个异步安全的POSIX方法列表,但这并没有告诉我们非POSIX方法,例如getpid().据推测,Linux添加的许多非POSIX方法中的一些是异步安全的,但我找不到列表.

还有这个答案声称所有直接(非多路复用)系统调用都是异步安全的,但没有提供任何证据.

目标是构建某种异步安全的线程本地存储,因为在一般情况下__thread 是不安全的.

它不一定是"Linux线程ID" - 任何一致的线程ID都可以.例如,pthread_self这将是伟大的,但没有任何声称是异步安全的.如果我们在glibc Linux中检查该方法的实现,它会延迟到THREAD_SELF宏,它看起来像:

# define THREAD_SELF \
({ struct pthread *__self;                                                  \
  asm ("movl %%gs:%c1,%0" : "=r" (__self)                                  \
          : "i" (offsetof (struct pthread, header.self)));                    \
  __self;}) 
Run Code Online (Sandbox Code Playgroud)

似乎是,这应该是异步安全的,如果有问题的线程用于填充制度下创建gs语域(也许是在Linux中的所有线程,我不知道).仍然看着那个标题让我非常害怕......

Max*_*kin 1

正如在异步信号安全访问 dlopen()ed 库中的 __thread 变量中提到的那样?您提供了(重点是我的):

当变量位于主可执行文件或直接链接的 DSO 中时,__thread 变量通常符合要求(至少在 Linux/x86 上)。

但是,当 DSO 被 dlopen()ed(并且不使用初始执行 TLS 模型)时, 从给定线程第一次访问 TLS 变量会触发对 malloc 的调用...

换句话说,它只需要对该线程特定变量进行一次访问即可使其生效并使其在信号处理程序中可用。例如:

  1. 创建子线程之前,在父线程中阻止您感兴趣的信号。
  2. 调用 后,在父线程中取消阻止那些有趣的信号pthread_create
  3. 在子线程中初始化__thread变量并解锁那些有趣的信号。

我通常将 unix 管道的写入端存储在该特定于线程的变量中,并且信号处理程序将信号号写入该管道。select/epoll管道的读取端在同一线程中注册,以便我可以处理信号上下文之外的信号。例如:

__thread int signal_pipe; // initialized at thread start

extern "C" void signal_handler(int signo, siginfo_t*, void*)
{
    unsigned char signo_byte = static_cast<unsigned>(signo); // truncate
    ::write(signal_pipe, &signo_byte, 1); // standard unix self pipe trick
}
Run Code Online (Sandbox Code Playgroud)