- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我正在使用 gtest 进行单元测试,特别是在调试版本中对某些断言使用了一些 DEATH_TESTS。为了 SetUp()
测试,我必须创建一个对象,它会创建另一个线程,关闭并执行一些工作,返回一些数据,然后加入对象的线程。最后,测试夹具的 SetUp()
返回,允许测试主体运行。
我注意到有时 DEATH_TEST 会提示 死亡测试使用 fork(),这在线程上下文中尤其不安全。对于此测试,Google Test 检测到 2 个线程。
这当然是一个有效问题,如果实际上有多个线程在运行。但是,有时不存在此类警告。这似乎是一种竞争条件。
所以仔细研究,我发现 gtest 使用 /proc/self/task
伪文件系统来发现线程。由于我的所有线程都已命名,因此我决定使用 /proc/self/task/[tid]/comm
来发现哪个线程可能会挥之不去。实际上,它与被 join()
编辑的线程完全相同。所以我想出了一个示例源代码来重现问题,1) 为 gtest 重现 gtest 的线程检测,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 发生变化。
在研究这个过程中,我发现系统的线程 ID(/proc/self/task/[tid]
中的[tid]
)不同于 pthread 的 pthread_t
符合 pthread_getname_np()
中的预期。我发现有 prctl
和 PR_GET_NAME
但它似乎只检索当前(调用)线程的名称。所以我的一个问题是:如果给定系统 TID,是否有一个记录的 API 来检索线程的名称(例如,这样您就不必阅读 /proc/self/task/[tid]/comm
)? 但这只是一个附带问题。
更重要的是,有没有办法保证就 fork()
问题而言这是误报?,以及相关问题:有没有比 join()
更好的方法来确保 std::thread
实际上已经完成?
最佳答案
我认为没有跟踪系统 TID <-> pthread ID 映射你自己你运气不好; pthread ID 是一个不透明的值,专门用于将它与特定于平台的进程抽象分离,我认为没有任何公共(public) API 可以提取它。
我认为您的 procfs 和 std::thread::join
/pthread_join
竞争可能是不可避免的,至少在目前的 Linux 实现中是这样。 pthread_join
等待内核清除已注册的内存位置并在线程退出期间发出 futex 信号。这发生在 mm_release
(linux/kernel/fork.c) 中,它在 do_exit
中间被调用,在所有任务统计之前结构已更新。我怀疑在 pthread_join
完成后立即遍历 procfs 很容易与剩余的进程拆卸竞争。
就您要解决的问题而言,这是一个令人不满意的答案,但我希望这对您有所帮助。
关于c++ - gtest DEATH_TEST 提示 fork() 和线程,但只有找到的线程已加入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27321913/
例如,我有一个父类Author: class Author { String name static hasMany = [ fiction: Book,
代码如下: dojo.query(subNav.navClass).forEach(function(node, index, arr){ if(dojo.style(node, 'd
我有一个带有 Id 和姓名的学生表和一个带有 Id 和 friend Id 的 Friends 表。我想加入这两个表并找到学生的 friend 。 例如,Ashley 的 friend 是 Saman
我通过互联网浏览,但仍未找到问题的答案。应该很容易: class Parent { String name Child child } 当我有一个 child 对象时,如何获得它的 paren
我正在尝试创建一个以 Firebase 作为我的后端的社交应用。现在我正面临如何(在哪里?)找到 friend 功能的问题。 我有每个用户的邮件地址。 我可以访问用户的电话也预订。 在传统的后端中,我
我主要想澄清以下几点: 1。有人告诉我,在 iOS 5 及以下版本中,如果您使用 Game Center 设置多人游戏,则“查找 Facebook 好友”(如与好友争夺战)的功能不是内置的,因此您需要
关于redis docker镜像ENTRYPOINT脚本 docker-entrypoint.sh : #!/bin/sh set -e # first arg is `-f` or `--some-
我是一名优秀的程序员,十分优秀!