Mik*_*ell 7 c++ linux pthreads
当我尝试从C++中的子POSIX线程打开/ proc/net/tcp时,它失败并显示"No such file or directory"错误.如果我尝试从父线程打开它,它每次成功,并且在父线程中打开/关闭它的过程然后使它在子线程中的大约三分之一的时间也成功.我可以100%的时间在子线程中打开/ proc/uptime而不会出现问题.这是一些可以使用"g ++ -Wall test.cc -o test -pthread"编译的示例代码:
#include <iostream>
#include <fstream>
#include <cstring>
#include <cerrno>
#include <pthread.h>
using namespace std;
void * open_test (void *)
{
ifstream in;
in.open("/proc/net/tcp");
if (in.fail())
cout << "Failed - " << strerror(errno) << endl;
else
cout << "Succeeded" << endl;
in.close();
return 0;
}
int main (int argc, char * argv[])
{
open_test(NULL);
pthread_t thread;
pthread_create(&thread, NULL, open_test, NULL);
pthread_exit(0);
}
Run Code Online (Sandbox Code Playgroud)
我在Linux内核3.2.0上使用Intel i5-2520M(2核*2个虚拟内核)的Ubuntu 12.04机箱上运行它.以下是连续6次运行上述代码的输出:
mike@ung:/tmp$ ./test
Succeeded
Failed - No such file or directory
mike@ung:/tmp$ ./test
Succeeded
Succeeded
mike@ung:/tmp$ ./test
Succeeded
Failed - No such file or directory
mike@ung:/tmp$ ./test
Succeeded
Failed - No such file or directory
mike@ung:/tmp$ ./test
Succeeded
Succeeded
mike@ung:/tmp$ ./test
Succeeded
Failed - No such file or directory
mike@ung:/tmp$
Run Code Online (Sandbox Code Playgroud)
值得注意的是,如果我使用fork而不是posix线程,我就没有这个问题.如果我使用fork,那么子进程在读取/ proc/net/tcp时没有问题
只需要输入几个数据点....看起来这是Linux中的回归,因为2.6.35似乎在100%的时间都可以工作.3.2.0 pukes大多数时候甚至在我的慢速旧Pentium M笔记本电脑上.
这种行为似乎是虚拟文件系统中的一种错误/proc。如果您在打开文件之前添加此代码:
system("ls -l /proc/net /proc/self/net/tcp");
Run Code Online (Sandbox Code Playgroud)
您将看到这/proc/net是一个到 的符号链接/proc/self/net,并且/proc/sec/net/tcp对于对 的两次调用都正确列出open_test,即使生成的线程调用失败也是如此。
编辑:我刚刚意识到上面的测试是假的,因为 self 指的是系统调用的 shell 进程,而不是这个进程。使用以下函数也可以揭示该错误:
void ls_command () {
ostringstream cmd;
cmd << "ls -l /proc/net "
<< "/proc/" << getpid()
<< "/net/tcp "
<< "/proc/" << syscall(SYS_gettid)
<< "/net/tcp";
system(cmd.str().c_str());
}
Run Code Online (Sandbox Code Playgroud)
您会发现生成的线程有时无法看到父级的/net/tcp文件。事实上它已经消失了,因为这是运行该ls命令的生成 shell 进程。
下面的解决方法允许子线程可靠地访问其/proc/net/tcp.
我的理论是,这是某种竞争条件错误,正确地将作为测试和解决方法,我修改了代码/proc/self线程条目设置为父状态和线程特定状态的正确混合。open_test以使用与线程关联的“进程标识符”,而不是尝试访问父进程的(因为/proc/self指的是父进程 ID,而不是线程的)。
编辑:正如证据表明的那样,该错误与父进程在/proc/self/...子线程有机会读取其状态之前清理其状态有关。我仍然认为这是一个错误,因为子线程在技术上仍然是进程的一部分。getpid()主线程调用前后还是一样的pthread_exit()。/proc父进程的条目应保持有效,直到所有子线程完成为止。虽然
Edit2:乔纳斯认为这可能不是一个错误。作为证据,有以下内容man proc:
/proc/[pid]/fd
...
在多线程进程中,该目录的内容是
如果主线程已经终止则不可用(通常是
通过调用 pthread_exit(3)) 进行联盟。
/proc/self但是,请在同一页面条目中考虑此条目man:
/进程/自身
该目录指的是访问/proc文件的进程
系统,并且与 /proc 目录相同
同一进程的进程ID。
如果人们相信这不是一个错误,因为线程和进程在 Linux 中被视为相同,那么线程应该有一个/proc/self可以工作的期望。当版本不再可用时,可以通过修改/proc/self为使用/proc/[gettid]值来轻松修复该错误,就像下面的解决方法一样。/proc/[getpid]
void * open_test (void *)
{
ifstream in;
string file = "/proc/net/tcp";
in.open(file.c_str());
if (in.fail()) {
ostringstream ss;
ss << "/proc/" << syscall(SYS_gettid) << "/net/tcp";
cout << "Can't access " << file
<< ", using " << ss.str() << " instead" << endl;
file = ss.str();
in.open(file.c_str());
}
if (in.fail())
cout << "Failed - " << strerror(errno) << endl;
else
cout << "Succeeded" << endl;
in.close();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1727 次 |
| 最近记录: |