fcntl与close-on-exec、execl

fcntl与close-on-exec

fcntl系统调用是控制文件描述符属性的通用POSIX(POSIX是一种通用的规范)方法。

//头文件:
#include <unistd.h>    
#include <fcntl.h>

//定义函数:
int fcntl(int fd, int cmd);
int fcntl(int fd, int cmd, long arg);
int fcntl(int fd, int cmd, struct flock * lock);

fd:文件描述符
cmd:对fd的操作,具体内容请参考:链接2
close-on-exec:子进程默认会继承父进程的所有文件描述符,但是如果某个文件描述符设置了close-on-exec,那么从父进程中继承得到的文件描述符会在子进程(fork生成子进程)中被关闭。实例如下:

#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>

int main()
{
    int pipefd[2];

    if (pipe(pipefd) == -1) {
        perror("pipe");
        exit(EXIT_FAILURE);
    }

    // 将管道的写端标记为 close-on-exec
    if (fcntl(pipefd[1], F_SETFD, FD_CLOEXEC) == -1) {
        perror("fcntl");
        exit(EXIT_FAILURE);
    }

    pid_t pid = fork();

    if (pid == -1) {
        perror("fork");
        exit(EXIT_FAILURE);
    }

    if (pid == 0) {
        // 子进程
        close(pipefd[0]);
        // ...
        exit(EXIT_SUCCESS);
    } else {
        // 父进程
        close(pipefd[1]);
        // ...
        exit(EXIT_SUCCESS);
    }
}

在 fork() 调用后,子进程会继承 pipefd[1] 这个文件描述符,但由于它已经被标记为 close-on-exec,子进程在执行任何操作之前就会将它关闭。

execl函数

execl函数:在代码中调用其他可执行程序,验证程序如下:

// test2.cpp
#include<iostream>
using namespace std;

int main(){

         cout<< "这是测试程序!" << endl;

        return 0;
}

生成可执行文件test2:

g++ test2.cpp -o test2
// test.cpp
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/types.h>
#include <string.h>

int main(int argc, char *argv[])
{
    // execl函数
    // int execl(const char *pathname, const char *arg, ...

    //  pathname: 要执行的文件的路径(推荐使用绝对路径)
    //  接下来的参数代表执行该文件时传递过去的argv[0], argv[1], ..., 最后一个参数必须用空指针(NULL)作结束.
    //  argv[0]是程序名称,argv[1],...为程序后面所需要跟着的参数

    if (fork() > 0)
    {
        printf("I'm parent process: pid: %d\n", getpid());
        sleep(1);
    }
    else
    {
        execl("./test2", "test2", NULL);                // 调用上面我们生成的可执行文件test2
        // execl("/bin/ps", "ps", "a", "u", "x", NULL); // 调用系统中的可执行文件

        printf("I'm child process: %d", getpid());
    }
    for (int i = 0; i < 3; i++)
    {
        printf("i=%d, pid: %d\n", i, getpid());
    }
}

输出:

I'm parent process: pid: 25554
这是测试程序!
i=0, pid: 25554
i=1, pid: 25554
i=2, pid: 25554

execl函数是没有返回值的,因为从调用该函数开始,用户区就被调用的二进制程序给替换掉了,已经不再受我们控制。所以可以看到在程序运行时,printf("I'm child process: %d", getpid())并没有执行

参考:链接1

posted @ 2022-05-07 22:10  好人~  阅读(45)  评论(0编辑  收藏  举报