C 为什么在fork之后关闭文件描述符会影响子进程?

C 为什么在fork之后关闭文件描述符会影响子进程?,c,linux,exec,fork,file-descriptor,C,Linux,Exec,Fork,File Descriptor,我想通过单击按钮在linux中运行程序,因此我编写了一个函数execute: void execute(const char* program_call, const char* param ) { pid_t child = vfork(); if(child == 0) // child process { int child_pid = getpid(); char *args[2]; // arguments for exec

我想通过单击按钮在linux中运行程序,因此我编写了一个函数
execute

void execute(const char* program_call, const char* param )
{
    pid_t child = vfork();

    if(child == 0) // child process
    {
        int child_pid = getpid();

        char *args[2]; // arguments for exec
        args[0] = (char*)program_call; // first argument is program_call
        args[1] = (char*)param;

        // close all opened file descriptors:
        const char* prefix = "/proc/";
        const char* suffix = "/fd/";
        char child_proc_dir[16]; 
        sprintf(child_proc_dir,"%s%d%s",prefix,child_pid, suffix);

        DIR *dir;
        struct dirent *ent;

        if ((dir = opendir (child_proc_dir)) != NULL) {
            // get files and directories within directory
            while ((ent = readdir (dir)) != NULL) {
                // convert file name to int
                char* end;
                int fd = strtol(ent->d_name, &end, 32);
                if (!*end) // valid file descriptor
                {
                    close(fd); // close file descriptor
                    // or set the flag FD_CLOEXEC
                    //fcntl( fd, F_SETFD, FD_CLOEXEC );
                }
            }
            closedir (dir);
        } 
        else 
        {
            cerr<< "can not open directory: " << child_proc_dir <<endl;
        }
        // replace the child process with exec*-function
            execv(program_call,args);
            _exit(2);
        }
    else if (child == -1) // fork error
    {
        if (errno == EAGAIN)
        {
            cerr<<“To much processes"<<endl;
        }
        else if (errno == ENOMEM)
        {
            cerr<<“Not enough space available."<<endl;
        }
    }
    else // parent process
    {
        usleep(50); // give some time 
        if ( errno == EACCES)
        {
            cerr<<“Permission denied or process file not executable."<<endl;
        }
        else if ( errno == ENOENT)
        {
            cerr<<"\n Invalid path or file."<<endl;
        }
        int child_status;
        if ( waitpid(child, &child_status, WNOHANG | WUNTRACED) < 0) // waitpid failed
        {
            cerr<<"Error - Execution failed"<<endl;
        }
        else if ( WIFEXITED( child_status ) &&  WEXITSTATUS( child_status ) != 0)   
        {
            cerr<<“Child process error - Execution failed"<<endl;
        }
    }
}
void执行(常量字符*程序调用,常量字符*参数)
{
pid_t child=vfork();
if(child==0)//子进程
{
int child_pid=getpid();
char*args[2];//exec的参数
args[0]=(char*)程序调用;//第一个参数是程序调用
args[1]=(char*)参数;
//关闭所有打开的文件描述符:
常量字符*前缀=“/proc/”;
常量字符*后缀=“/fd/”;
char child_proc_dir[16];
sprintf(子进程目录,“%s%d%s”,前缀,子进程pid,后缀);
DIR*DIR;
结构导向;
if((dir=opendir(child\u proc\u dir))!=NULL){
//获取目录中的文件和目录
while((ent=readdir(dir))!=NULL){
//将文件名转换为int
字符*结束;
int fd=strtol(ent->d_name,&end,32);
if(!*end)//有效的文件描述符
{
关闭(fd);//关闭文件描述符
//或者设置标志FD_CLOEXEC
//fcntl(fd、F_SETFD、fd_CLOEXEC);
}
}
closedir(dir);
} 
其他的
{

cerr首先,在2014年,永远不要使用
vWork
,而只是简单地使用(因为自POSIX 2001年以来已过时,并在POSIX 2008年删除)

然后,关闭大多数文件描述符的最简单方法就是

for (int fd=3; fd<256; fd++) (void) close(fd);

for(int-fd=3;fd第一个问题:没有办法阻止文件描述符的继承,除非您自己关闭它们或设置
fd\u-CLOEXEC
,检查

第二个问题:您得到了waitpid的返回值通常为0,因为您在
waitpid
中分离了
WNOHANG

waitpid(): on success, returns the process ID of the child whose state has changed; 
if WNOHANG was specified  and  one  or  more  child(ren) specified by pid exist, 
but have not yet changed state, then 0 is returned.  On error, -1 is returned.

AFAIK文件描述符在子级和父级之间共享。您必须使用
dup(2)创建原始描述符的副本
在子进程中,并且仅在子进程中使用此副本。您的应用程序在做什么?它使用什么文件描述符?如何使用您的
执行
?我的应用程序应该是其他应用程序的简单启动面板。它现在不使用任何无关的文件描述符,但以后可能会更改。执行在按钮回调函数(FLTK)。@Philipp Murry:只使用dup2()中的重复文件描述符有什么好处?使用
dup
您只会得到一个新的文件描述符;一个独立于第一个文件描述符的描述符。这就像再次调用文件上的
open
。因此,关闭第一个文件描述符不会影响第二个文件描述符(使用
dup
创建的副本)。我不鼓励使用for循环来关闭所有文件描述符,因为您可能会关闭有效的文件描述符。我看到这样的代码会中断,因为有人在该循环之前打开了一个文件,然后使用了该文件描述符。您是否愿意详细说明为什么不鼓励使用vWork?
fork
足够快了(因为写分页时的延迟复制)。
vWork
是无用的。请参阅。注意,它不在POSIX 2008中(在POSIX 2001中已过时)@BasileStarynkevitch我认为vfork在很大程度上是无害的,而且很可能是更好的,尽管现在已经从posix中删除了,但是从vfork迁移的最佳路径是posix_spawn,因为它比其中任何一个都快,并且可以立即执行另一个程序,避免逻辑错误的可能性。看起来你在执行某种任务,Basile。如果您所在的系统允许vWork共享地址空间,并且不允许过度使用虚拟内存,那么vWork不是“无用的”。并且在vWorked进程中以独占方式操作文件描述符是安全的(例如,从输出设置管道),正如复制的那样。话虽如此,OP的示例代码在vWork中确实存在一些巨大的问题,因为它会严重干扰子程序中的堆栈。我的应用程序应该像其他程序的开始面板一样工作,所以我需要指定WNOHANG,否则——正如我所知——我不能一次调用多个程序。我只想获得inf如果exec无法找出失败的原因并显示消息,则进行格式化。问题是,waitpit不可靠会返回-1表示失败。我认为您最好为
SIGCHLD
设置一个处理程序,当一个程序在exec上失败时,您将得到信号
SIGCHLD
。这比使用
WNOHANG
检查它要健壮得多<代码>等待PID