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

时间:2014-02-13 02:14:49

标签: linux gcc pthreads signals posix

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

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

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

它不一定是“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;}) 
如果所讨论的线程是在填充gs resgister的制度下创建的,那么它似乎似乎应该是异步安全的(也许Linux中的所有线程都是,我我不确定。仍在看that header让我非常害怕......

1 个答案:

答案 0 :(得分:1)

正如您提供的Async-signal-safe access to __thread variables from dlopen()ed libraries?中提到的(强调是我的):

  

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

     

但是当DSO是dlopen()ed(并且不使用initial-exec TLS模型)时,   从给定线程首次访问TLS变量会触发对其的调用   的malloc ...

换句话说,它只需要访问该特定于线程的变量就能使其生效并使其在信号处理程序中可用。 E.g:

  1. 在创建子线程之前,阻止您在父线程中感兴趣的信号。
  2. 在调用pthread_create后,在父线程中取消阻止这些有趣的信号。
  3. 在子线程中初始化您的__thread变量并取消阻止这些有趣的信号。
  4. 我通常将unix管道的写入端存储在特定于胎面的变量中,信号处理程序将信号编号写入该管道。管道的读取端在同一个线程中注册select/epoll,以便我可以处理信号上下文之外的信号。 E.g:

    __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
    }