如何解决即使我关闭了所有文件,某些管道文件描述符仍保持打开状态
static int pipefd[2];
static pid_t cpid = 0;
void sigtimeout(int num) {
kill(cpid,9);
close(pipefd[1]);
close(pipefd[0]);
pipe(pipefd);
write(pipefd[1],"T/O\n",5);
}
void settimer(float time) {
struct itimerval timer;
timer.it_value.tv_sec = (int)time;
timer.it_value.tv_usec = (timeout - (int)time) * 1000000;
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_usec = 0;
setitimer(ITIMER_REAL,&timer,NULL);
}
pid_t popen2(char *cmd) {
if (pipe(pipefd) == -1)
return -1;
int pid;
if ((pid = fork()) == -1)
return -1;
if (pid == 0) {
close(STDIN_FILENO);
close(STDERR_FILENO);
dup2(pipefd[1],STDOUT_FILENO);
close(pipefd[0]);
close(pipefd[1]);
execlp("sh","sh","-c",cmd,NULL);
_exit(EXIT_SUCCESS);
} else
settimer(timeout);
return pid;
}
void getcmd(const Block *block,char *output)
{
if (block->signal)
{
output[0] = block->signal;
output++;
}
strcpy(output,block->icon);
char *cmd;
if (button)
{
cmd = strcat(exportstring,block->command);
cmd[14] = '0' + button;
cpid = popen2(cmd);
if (cpid == -1) {
close(pipefd[0]);
close(pipefd[1]);
return;
}
cmd[16] = '\0';
}
else
{
cmd = block->command;
cpid = popen2(cmd);
if (cpid == -1) {
close(pipefd[0]);
close(pipefd[1]);
return;
}
}
button = 0;
waitpid(cpid,0);
settimer(0);
kill(cpid,9);
close(pipefd[1]);
int i = strlen(block->icon);
read(pipefd[0],output+i,CMDLENGTH-i-delimLen);
close(pipefd[0]);
for (char *c = output; *c; c++)
if (*c == '\n') {
c[1] = '\0';
break;
}
i = strlen(output);
if (delim[0] != '\0') {
//only chop off newline if one is present at the end
i = output[i-1] == '\n' ? i-1 : i;
strncpy(output+i,delim,delimLen);
}
else
output[i++] = '\0';
}
所以我正在尝试修改 dwmblocks 以添加超时功能。这样,如果命令挂起,整个状态栏就不会冻结。
似乎一切正常,但有一个小问题。
我的代码使我的整个 linux 系统崩溃,因为它每次运行命令时都会打开一些文件描述符。您可能知道,Linux 对此有保护措施,因此我系统上所有其他尝试打开文件描述符的应用程序也会崩溃。
事实是,我实际上是在关闭我在代码中打开的每个管道,即使是在您 fork 时自动打开的管道。我就是想不通是什么问题。
我非常感谢您的帮助。
顺便说一句:我只是把相关的代码放在这里,因为问题出在文件描述符上。这是我在代码中处理文件描述符的唯一地方。
如果您觉得它在某种程度上相关,请随意询问代码的更多部分:)
解决方法
您的 popen2()
函数将父进程中的两个管道端保持打开状态。父进程应始终关闭写入端(子进程写入的)。也许这就是泄漏的那个。
如果您要打印 (int)getpid()
以显示进程 ID,您可以在 /proc/PID/fd/
中列出伪文件,因为它们描述了进程当前打开的文件描述符。 (如果您将 ls -laF /proc/PID/fd/
与进程 ID 号一起使用而不是 PID
,您甚至可以看到描述符打开的内容/位置。)
在 this answer here 中,我最近展示了如何实现 safe_pipe()
、run()
和 wait_all_children()
函数来探索子进程之间的复杂管道方案。 safe_pipe()
默认为每个管道描述符设置 close-on-exec 标志,并且 run()
仅在使用此类描述符的子进程中清除该标志,因此分叉的子进程没有其他管道的描述符完全打开。包含的 example.c 还显示了当子进程启动时父进程必须如何关闭子进程使用的所有管道末端,以便子进程正确检测输入的结束。 (如果父进程打开了写入端,则它可以写入管道,因此从该管道的读取端读取的任何子进程将永远不会看到输入结束。)
如果有必要或有帮助,我愿意解释 safe_pipe()
和 run()
和 wait_all_children()
如何做他们所做的事情,以及为什么。特别是,run()
在 exec 之前的子进程和父进程之间使用额外的管道来检测执行指定二进制文件的问题(和其他错误)。虽然其中可能有错别字,但两者都是非常健壮的实现,不会泄漏资源等。
好尴尬哈哈哈
我的 settimer 函数有一个错字:超时应该是时间。
所以真正的问题在于赛车状况,尽管我的管道系统远非完美。
这说明错误有时很难调试。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。