检查线程是否为boost线程。

4
为了进行线程本地清理,我需要创建一个断言来检查当前线程是否是通过boost::thread创建的。如何检查这一点?也就是说,如何检查当前线程是否由boost::thread处理?
我只需要在线程退出时清理线程本地存储,而Boost的thread_local_ptr似乎只能在线程本身是boost线程的情况下工作。
请注意,我不是在清理时进行检查,而是在线程生命周期中的某个时刻进行检查。某些函数调用我们的API /回调(间接地)导致我分配线程本地存储。只有boost线程可以这样做,因此我需要在那个时刻检测线程是否不是boost线程。
请参考线程本地存储中静态类成员的销毁问题,针对没有通用清理处理程序的问题。我回答了这个问题并意识到pthread_cleanup_push实际上不起作用:它不会在线程的干净退出时被调用。
虽然我没有检测 Boost 线程的答案,但所选答案确实解决了我的问题根源。Boost thread_specific_ptr 可以在任何 pthread 中调用它们的清理函数。因为一个隔离的测试表明它确实有效,所以必须是其他原因导致它不起作用。

6
我认为你并不需要一个“静态”断言。静态断言在编译时进行检查,但这时期检查运行时如何创建某些内容太早了。我认为你只需要一个普通的断言。 - Rob Kennedy
我已经修正了静态断言。 - edA-qa mort-ora-y
3个回答

3
您的问题前提是错误的 :) boost::thread_specific_ptr 即使线程不是boost线程也可以工作。想一想--对于主线程来说,由于它不可能被boost创建,那么如何为其创建线程特定存储呢?我已经在主线程中成功使用了boost::thread_specific_ptr,虽然我没有检查过boost::thread_specific_ptr的实现,但最明显的实现方式即使针对非boost线程也能正常工作。大多数操作系统都允许您获取当前线程的唯一ID号,然后您可以将其用作映射/数组/哈希表的索引。

更有可能的是,您遇到了其他导致您期望看到的行为未发生的bug。您应该打开一个单独的问题,并提供一个小型可编译代码示例来说明意外行为。


我正在努力弄清楚它是如何工作的。哪个pthread函数使其起作用?我正在运行测试来验证这是否属实。 - edA-qa mort-ora-y
明白了,调用pthread_key_create时可以接受一个析构函数。这对我来说已经足够好了,但是如果线程不是通过pthread创建的,会怎么样呢? ;) - edA-qa mort-ora-y
我实际上在考虑pthread_self(),它为当前线程提供一个唯一的整数。pthread_key*函数可能更有效率;我记得在Linux的ELF ABI中,它们专门支持线程本地存储,这让我想到CPU必须有直接支持它的特殊寄存器,并且pthread_key_*可以利用它们。至于如果它不是通过pthread创建的——你开玩笑,但如果操作系统上有多个线程实现可用,那么它们都会归结为相同的核心,所以事情很可能会正常工作。 - Joseph Garvin
这个在Windows上如何实现的提示? - Marc Glisse
引用自http://www.boost.org/doc/libs/1_53_0/doc/html/thread/thread_local_storage.html:“在某些平台上,对于使用平台本地API创建的线程,线程特定数据的清理不会执行。” - Marc Glisse

0
每次一个boost线程结束时,所有的线程特定数据都会被清除。TSD是一个指针,在销毁/重置时调用delete p*
可选地,可以为每个项目调用一个清理处理程序,而不是delete p*。该处理程序在TLS构造函数中指定,并且您可以使用清理函数来进行一次性清理。
#include <iostream>
#include <boost/thread/thread.hpp>
#include <boost/thread/tss.hpp>

void cleanup(int* _ignored) {
    std::cout << "TLS cleanup" << std::endl;
}

void thread_func() {
    boost::thread_specific_ptr<int> x(cleanup);
    x.reset((int*)1); // Force cleanup to be called on this thread

    std::cout << "Thread begin" << std::endl;
}

int main(int argc, char** argv) {
    boost::thread::thread t(thread_func);

    t.join();

    return 0;
}

问题是,如果线程不是 boost::thread,这是否确保清理数据? - edA-qa mort-ora-y

0

使用静态断言是不可能做到这一点的:这意味着你可以在编译时检测到它,而这是不可能的。

不过,如果你指的是运行时检查:

如果您不将boost::thread与其他方法混合使用,那么问题就消失了。任何创建线程的库都应该已经自动处理其自己的线程(或者通过API文档记录必须调用的关闭函数)。

否则,您可以保留一个容器,其中包含所有未使用boost::thread创建的pthread_t,并在关闭时检查线程是否在容器中。如果它不在容器中,那么它就是使用boost::thread创建的。

编辑:您是否考虑过设置您的应用程序,以便API回调只能发生在使用boost::thread创建的线程中?这样做可以预防问题,并且消除了进行检查的需要,即使存在这种检查,实现起来也很麻烦。


抱歉,是的,运行时断言。问题出在从第三方库回调到我们代码上。 - edA-qa mort-ora-y

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接