gtest DEATH_TEST抱怨fork()和线程,但是只有线程被join

我正在使用gtest进行unit testing,特别是在debugging版本中有一些DEATH_TESTS的断言。 要设置SetUp()testing,我必须创build一个对象,创build另一个线程,closures并做一些工作,返回一些数据,然后join对象的线程。 最后,testing夹具的SetUp()返回,允许testing体运行。

我注意到有时DEATH_TEST会抱怨Death tests use fork(), which is unsafe particularly in a threaded context. For this test, Google Test detected 2 threads. Death tests use fork(), which is unsafe particularly in a threaded context. For this test, Google Test detected 2 threads. 如果实际上有多个线程正在运行 ,这当然是一个有效的问题。 然而,有时候,这样的警告不存在。 这似乎是一个竞争条件。

所以看着它,我发现gtest正在使用/proc/self/task伪文件系统来发现线程。 由于我所有的线程都被命名,我决定使用/proc/self/task/[tid]/comm来发现哪个线程可能存在。 事实上,这是完全相同的线程是join()编辑。 所以我想出了一个例子源代码来重现这个问题: 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; } 

使用Ubuntu 14.04和GCC 4.8.2-19ubuntu1以及在示例源代码的第一行中注释的命令,我最终输出到stdout,表明竞争条件似乎确实存在。 大多数输出​​状态为“未find”,而有时输出会散布在TARGET命名的线程的TID中。 我可以禁用“未find”的输出,并观察发射的TID改变。

在这个过程中,我发现系统的线程ID( /proc/self/task/[tid] )与pthread的pthread_t不同,正如pthread_getname_np()所期望的那样。 我发现有PR_GET_NAME prctl ,但似乎只检索当前(调用)线程的名称。 所以我的一个问题是: 是否有一个logging的API来检索一个线程的名字,如果给定一个系统TID(例如,所以你不必读取/proc/self/task/[tid]/comm )? 但这只是一个侧面的问题。

更重要的是,有没有办法保证fork()问题是一个误报? ,和相关的问题: 是否有更好的方法来确保一个std::thread已经完成比join()

  1. 我认为,无线跟踪系统TID < – > pthread ID映射自己,你是运气不好; pthread ID是一个不透明的值,专门将其从平台特定的进程抽象中分离出来,我不相信有任何公共API可以提取它。

  2. 我认为你的procfs& std::thread::join / pthread_join比赛可能是不可避免的,至少在目前的Linux实现中。 pthread_join等待内核清除已注册的内存位置并在线程退出期间发出futex信号。 这发生在mm_releaselinux / kernel / fork.c )中,在所有的任务记账结构被更新之前,它在do_exit中间被调用。 我怀疑在pthread_join完成之后立即遍历procfs可以轻松地与其余的进程拆卸进行竞争。

一个令人不满的答案就你想解决的问题,但我希望这有助于。