我使用gtest進行單元測試,特別是在調試版本中對某些斷言有一些DEATH_TESTS。對於SetUp()
測試,我必須創建一個對象,它創建另一個線程,關閉並執行一些工作,返回一些數據,然後加入對象的線程。最後返回測試夾具的SetUp()
,允許測試體運行。gtest DEATH_TEST抱怨fork()和線程,但只發現線程已加入
我注意到,有時DEATH_TEST會抱怨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()
版。因此,我想出了一個示例源代碼來重現gtest的gtest線程檢測問題,如果目標線程滯留,然後向stdout發送消息,則會返回問題2)。
// 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指示爭用條件似乎存在。大多數輸出狀態爲「未找到」,而有時輸出會散佈TARGET命名線程的TID。我可以禁用「未找到」的輸出並觀察發出的TID改變。
在這方面的工作,我發現,隨着預期pthread_getname_np()
系統的線程ID([tid]
在/proc/self/task/[tid]
)是並行線程的pthread_t
不同。我發現prctl
與PR_GET_NAME
但似乎只檢索當前(調用)線程的名稱。所以我的一個問題是:是否有一個記錄的API來檢索一個線程的名稱,如果給定一個系統TID(例如,所以你不必讀/proc/self/task/[tid]/comm
)?但這只是一個側面的問題。
更重要的是,有沒有辦法保證這是一個誤報,只要fork()
問題有關?,以及相關的問題:有沒有更好的方法來確保std::thread
實際上已經完成比join()
?
您看過這篇文章:https://code.google.com/p/googletest/wiki/AdvancedGuide#Death_Tests_And_Threads?他們提到「衆所周知的線程存在的問題 - 但我不知道這個問題...... – PiotrNycz 2015-01-02 08:03:56
是的,我讀過它,這就是我的問題試圖討論 - 試圖確保只有存在一個單線程(主線程)。我使用的所有靜態庫都不會創建自己的線程。此外,我提供了一個沒有第三方靜態庫的MCVE。 – inetknght 2015-01-02 15:13:47