0


fork函数如何创建进程,exit/_exit函数如何使进程终止的详细分析与代码实现

🎊【进程通信与并发】专题正在持续更新中,进程,线程,IPC,线程池等的创建原理与运用✨,欢迎大家前往订阅本专题,获取更多详细信息哦🎏🎏🎏

🪔本系列专栏 - ​​​​​​并发与进程通信

🍻欢迎大家 🏹 点赞👍 评论📨 收藏⭐️

📌个人主页 - 勾栏听曲_0的博客📝

🔑希望本文能对你有所帮助,如有不足请指正,共同进步吧🏆

🎇我见青山多妩媚,料青山见我应如是。📈

fork创建进程

介绍

    fork用来创建一个新进程(child proccess),你要创建一个新进程,首先得知道一个进程中都包含上面东西。
    系统数据

    用户数据

    指令
     fork一个新进程时,这个新进程的 数据 和 指令 来源于哪里呢?

            来源于它爸爸(父进程,调用fork的那个进程)

    fork这个函数在创建子进程时,都复制了父进程的哪些内容呢:  

            copy了父进程的数据和指令!!!
             父进程的变量,数据对象,
             标准IO缓冲区
             文件描述符
             ...
             copy完了后,父子进程就独立啦。

        通过fork的不同的返回值,来区分到底是父进程返回,还是子进程返回。

接口

头文件

        #include <sys/types.h>
         #include <unistd.h>
    函数功能

        创建一个子进程

    函数原型
         pid_t fork(void);
    函数参数

        无

    函数返回值

        如果失败返回-1,同时errno被设置。

        如果成功:  

            父进程返回 子进程的pid( > 0) 

            子进程返回  0

代码实例

    以下是获取自己的进程ID与获取父进程的IP的函数

            头文件 
            #include <sys/types.h>
             #include <unistd.h>
        函数原型 
            pid_t getpid(void);  //用于获取自己的进程pid 
             pid_t getppid(void); //用于获取父进程的pid 
    以下代码实现创建一个子进程,并且父子进程分别输出自己的id。
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>

int main()
{
    pid_t pid = fork();
    if(-1 == pid)
    {
        perror("fork failed!");
        return -1;
    }
    else if(0 == pid)    //子进程
    {
        printf("这是子进程,我的ID为%d\n",getpid());
        printf("这是子进程,我的父进程ID为%d\n",getppid());
    }
    else if(pid > 0)
    {
        printf("这是父进程,我的ID为%d\n",getpid());
        printf("这是父进程,我的子进程ID为%d\n",pid);
        printf("这是父进程,我的父进程ID为%d\n",getppid());;
    }
    return 0;
}

思考

    (1) fork一旦成功,就会有父进程和子进程,那么fork之后,到底是父进程先执行,还是子进程先执行呢?

    (2)fork子进程会拷贝父进程的指令和数据,它到底拷贝了父进程哪些数据呢? 
                a:父进程全部的用户数据
                 b:父进程打开的文件描述符及状态
                 c:标准IO的缓冲区  
                 d:信号的处理方式
     (3)fork之后的子进程与父进程有什么区别?
            进程ID不同。子进程可以通过getpid()函数获取自己的进程ID,可以通过getppid()函数获取父进程的进程ID。
             子进程中的tms_utime tms_stime tms_cutime 和 tms_ustime的值设为0。
             子进程不继承父进程设置的文件锁,但继承了父进程中的所有互斥锁、读写锁和条件变量(包括它们的状态)。
             子进程拥有自己独立的地址空间,但是在fork之后exec之前两个进程用的是同一份物理页面。
             子进程的执行顺序和父进程是不确定的,取决于系统调度。

终止进程

    进程的终止一般有两种情况:第一是自己退出,常见的方法为main函数返回值,程序退出。第二种情况就是调用一些进程退出函数执行终止进程,例如exit/_exit函数与wait/waitpid函数。接下来外面就重点来讲解这两类程序退出函数。

exit/_exit函数

    exit函数和_exit函数都是用来终止进程的,但它们有以下区别:

            exit函数在终止进程之前,会先执行一些清理操作,比如调用atexit注册的函数,刷新所有文件缓冲区,关闭所有打开的文件描述符,销毁线程本地对象等。_exit函数则直接进入内核,不做任何清理操作。

            exit函数的参数是一个无符号整型,表示进程的退出状态,只有第八位有效(0-255),超出255将表示未定义退出状态值。_exit函数的参数是一个整型,表示进程的退出状态,但不一定是0-255。

            exit函数是标准C库函数,定义在<stdlib.h>头文件中。_exit函数是POSIX系统调用,定义在<unistd.h>头文件中。

接口

    头文件 
                 #include <stdlib.h>
            函数功能 

                让进程退出,正常退出,做一些清理工作(如:把缓冲区的内容,同步到文件中去)

            函数原型
                void exit(int status);
            函数参数

                int status    //表示退出码,表示退出状态,退出码的具体含义,由程序员来解释。    
             函数返回值 

                无

             头文件  
                 #include <unistd.h>
            函数功能

                _exit 坐火箭走的,让中止进程,来不及做清理工作

            函数原型 
                 void _exit(int status);
            函数参数  

                int status    //表示退出码,表示退出状态,退出码的具体含义,由程序员来解释。

            函数返回值

                无

代码实例

    你可以使用命令行参数来指定文件名和打开模式,然后根据模式来调用exit()函数或_exit()函数。例如,你可以输入
./a.out test.txt w

来打开test.txt文件并写入内容,或者输入

./a.out test.txt r _exit

来打开test.txt文件并读取内容,然后调用_exit()函数。

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

int main(int argc, char *argv[])
{
    if (argc < 3) // 检查命令行参数是否足够
    {
        printf("Usage: %s filename mode [exit_mode]\n", argv[0]); // 输出用法提示
        return 1;
    }
    char *filename = argv[1]; // 获取文件名
    char *mode = argv[2]; // 获取打开模式
    char *exit_mode = argv[3]; // 获取退出模式
    FILE *fp = fopen(filename, mode); // 打开文件
    if (fp == NULL) // 检查文件是否打开成功
    {
        printf("Cannot open file %s\n", filename); // 输出错误信息
        return 2;
    }
    if (strcmp(mode, "w") == 0) // 如果是写入模式
    {
        printf("Writing to file %s\n", filename); // 输出提示信息
        fprintf(fp, "Hello, file!\n"); // 写入内容到文件
    }
    else if (strcmp(mode, "r") == 0) // 如果是读取模式
    {
        printf("Reading from file %s\n", filename); // 输出提示信息
        char buffer[100]; // 定义缓冲区
        while (fgets(buffer, 100, fp) != NULL) // 循环读取文件内容
        {
            printf("%s", buffer); // 输出文件内容到标准输出
        }
    }
    else // 如果是其他模式
    {
        printf("Invalid mode %s\n", mode); // 输出错误信息
        fclose(fp); // 关闭文件
        return 3;
    }
    fclose(fp); // 关闭文件
    if (exit_mode != NULL && strcmp(exit_mode, "_exit") == 0) // 如果指定了_exit()函数
    {
        _exit(0); // 调用_exit()函数
    }
    else // 否则
    {
        exit(0); // 调用exit()函数
    }
    
}
标签: linux c语言 fork

本文转载自: https://blog.csdn.net/weixin_53050357/article/details/130408949
版权归原作者 勾栏听曲_0 所有, 如有侵权,请联系我们删除。

“fork函数如何创建进程,exit/_exit函数如何使进程终止的详细分析与代码实现”的评论:

还没有评论