C++ gtest DEATH_TEST抱怨fork()和线程,但只有找到的线程被连接

C++ gtest DEATH_TEST抱怨fork()和线程,但只有找到的线程被连接,c++,linux,multithreading,c++11,fork,C++,Linux,Multithreading,C++11,Fork,我使用gtest进行单元测试,特别是对调试构建中的一些断言进行死亡测试。为了SetUp()测试,我必须创建一个对象,该对象创建另一个线程,执行一些工作,返回一些数据,然后在对象的线程上连接。最后,测试夹具的SetUp()返回,允许测试主体运行 我注意到,有时死亡测试会抱怨死亡测试使用fork(),这在线程上下文中尤其不安全。对于此测试,Google test检测到2个线程。如果实际上有多个线程在运行,这当然是一个有效的问题。然而,有时,这种警告并不存在。这似乎是一种竞赛条件 因此,深入研究它,我

我使用gtest进行单元测试,特别是对调试构建中的一些断言进行死亡测试。为了
SetUp()
测试,我必须创建一个对象,该对象创建另一个线程,执行一些工作,返回一些数据,然后在对象的线程上连接。最后,测试夹具的
SetUp()
返回,允许测试主体运行

我注意到,有时死亡测试会抱怨死亡测试使用fork(),这在线程上下文中尤其不安全。对于此测试,Google test检测到2个线程。如果实际上有多个线程在运行,这当然是一个有效的问题。然而,有时,这种警告并不存在。这似乎是一种竞赛条件

因此,深入研究它,我发现gtest正在使用
/proc/self/task
伪文件系统来发现线程。由于我所有的线程都已命名,我决定使用
/proc/self/task/[tid]/comm
来发现哪个线程可能会延迟。实际上,它与
join()
ed的线程完全相同。因此,我提出了一个示例源代码来重现问题1)重现gtest对gtest的线程检测,2)如果目标线程延迟,则向stdout发出消息

// g++ test.cpp --std=c++11 -pthread
#include <iostream>
#include <fstream>
#include <string>
#include <thread>

#include <dirent.h> // DIR*, dirent*, opendir(), closedir(); enumerate pseudo-fs /proc/self/task
#include <string.h> // strcmp();

#include <sys/prctl.h> // prctl(), PR_SET_NAME; sets name of current thread

std::string get_thread_name(std::string tid_str) {
    std::fstream f(std::string("/proc/self/task/") + tid_str + std::string("/comm"));
    tid_str.clear();
    std::getline(f, tid_str);
    return tid_str;
}

int main(int argc, char **argv) {
    // until SIGTERM (ctrl-c)
    while (true) {
        std::thread a([](){
            prctl(PR_SET_NAME,"TARGET",0,0,0);
        });
        a.join();
        if (DIR *dir = opendir("/proc/self/task")) {
            bool found = false;
            while (dirent *entry = readdir(dir)) {
                if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
                    std::string name = get_thread_name(entry->d_name);
                    if ( found = (name == "TARGET") ) {
                        std::cout << "THREAD " << entry->d_name << " -- " << name << std::endl;
                    }
                }
            }
            closedir(dir);
            if ( not found ) {
                std::cout << "Not found" << std::endl;
            }
        } else {
            std::cout << "Cannot enumerate" << std::endl;
        }
    }

    return 0;
}
//g++test.cpp--std=c++11-pthread
#包括
#包括
#包括
#包括
#包括//DIR*、dirent*、opendir()、closedir();枚举伪fs/proc/self/task
#包括//strcmp();
#包括//prctl(),PR\u SET\u名称;设置当前线程的名称
std::string get\u thread\u name(std::string tid\u str){
std::fstream f(std::string(“/proc/self/task/”)+tid_str+std::string(“/comm”);
tid_str.clear();
标准::getline(f,tid_str);
返回tid_街;
}
int main(int argc,字符**argv){
//直到SIGTERM(ctrl-c)
while(true){
std::线程a([])(){
prctl(PRU集合名称,“目标”,0,0,0);
});
a、 join();
if(DIR*DIR=opendir(“/proc/self/task”)){
bool-found=false;
while(dirent*entry=readdir(dir)){
如果(strcmp(条目->数据单元名称“.”)=0和&strcmp(条目->数据单元名称“…”)!=0){
std::string name=get\u thread\u name(entry->d\u name);
如果(找到=(名称=“目标”)){
标准::cout
  • 我认为w/o跟踪系统TID pthread ID自己映射你就不走运了;pthread ID是一个不透明的值,专门用于将它与特定于平台的流程抽象分离,我不相信有任何公共api来提取它

  • 我认为您的procfs&
    std::thread::join
    /
    pthread\u join
    竞争可能是不可避免的,至少在当前的Linux实现中是如此。
    pthread\u join
    等待内核清除注册的内存位置,并在线程退出时发出futex信号。这发生在
    mm\u release
    (Linux/kernel/fork.c)在所有的任务计费结构被更新之前,它在“代码> DOSEXECUT/CODE”的中间被调用。我怀疑在<代码> pthRead加入/<代码>完成之后遍历PROFS可以很容易地与剩余的进程拆卸竞争。


  • 对于您试图解决的问题,答案令人不满意,但我希望这会有所帮助。

    您读过这篇文章吗:?他们提到“在线程存在的情况下分叉的众所周知的问题”-但我不知道这个问题…是的,我已经读过了,这就是我的问题试图讨论的内容-试图确保只有一个线程存在(主线程)。我使用的所有静态库都不会创建它们自己的线程。此外,我提供了一个没有第三方静态库的MCVE。在某些方面令人不满意,但它确实为我指明了在内核中读取的方向。这至少是有帮助的。看起来相同的
    do\u exit
    函数尝试设置
    tsk->state=TASK_死了
    。我想知道Linux内核的未来版本是否可以将任务状态设置为某种状态,表明在执行任何连接信号释放执行之前任务正在退出。然后可以对其进行检查和轮询?在google上搜索“Linux get task state”如果给定pid或tid,则不会显示检索任务状态的API。我需要更多的研究。