当前位置: 首页> 文旅> 艺术 > 企业公示信息查询系统四川_网页设计教程课本_百度手机助手下载2021新版_苏州网站排名推广

企业公示信息查询系统四川_网页设计教程课本_百度手机助手下载2021新版_苏州网站排名推广

时间:2025/7/10 3:01:06来源:https://blog.csdn.net/weixin_65931202/article/details/145599168 浏览次数:1次
企业公示信息查询系统四川_网页设计教程课本_百度手机助手下载2021新版_苏州网站排名推广

目录

一、进程创建

1. fork函数初识

2. fork函数返回值的意义

3. 写时拷贝(Copy-On-Write, COW)

4.fork的常规用法

5. fork调用失败的原因

二、进程终止

1.  终止的本质

2. main函数的return返回值

3. 进程退出状态的含义

4. 父进程为什么会得到子进程的退出码?

5. 异常退出与信号

6.  进程常见终止情况

7. exit 和 _exit 的区别

8. return与exit的区别


一、进程创建

1. fork函数初识

        在Linux系统中,fork()函数是创建进程的核心工具。它通过复制现有进程(父进程)来创建新进程(子进程)。

函数声明:

#include <unistd.h>pid_t fork(void);

返回值:

  • 子进程中返回0

  • 父进程中返回子进程的PID(进程ID)。

  • 如果出错,返回-1


fork函数的工作原理:

进程调用fork时,当控制转移到内核中的fork代码后,内核会执行以下操作:

  1. 分配新的内存块和内核数据结构给子进程。

  2. 将父进程的部分数据结构内容拷贝至子进程。

  3. 将子进程添加到系统进程列表中。

  4. fork返回后,调度器开始调度。

当一个进程调用fork之后,就有两个二进制代码相同的进程。而且它们都运行到相同的地方。但每个进程都将可以开始它们自己的旅程,看如下程序。

示例代码:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>int main()
{pid_t pid;printf("Before: pid is %d\n", getpid());  // 打印当前进程IDif ((pid = fork()) == -1) {perror("fork()");  // 出错处理exit(1);}printf("After: pid is %d, fork return %d\n", getpid(), pid);sleep(1);  // 延迟1秒return 0;
}

运行结果:

这里看到了三行输出,一行Before,两行After。进程61200先打印Before消息,然后它又打印After。另一个After消息是由61201打印的。我们注意到进程61201没有打印Before,为什么呢?如下图所示:

分析:

  • 父进程(PID=61200)先打印Before消息,然后调用fork创建子进程(PID=61201)。

  • 父进程和子进程各自打印After消息。子进程没有打印Before消息,因为它是在fork之后才创建的。

  • 所以,fork之前父进程独立执行,fork之后,父子两个执行流分别执行。注意,fork之后,谁先执行完全由调度器决定。


经典面试题连续调用两次fork会创建多少进程?

fork();
fork();

答案:总共会创建3个子进程(2^n-1公式)

2. fork函数返回值的意义

  • 子进程返回0:子进程需要知道自己是子进程,返回0是一个约定。

  • 父进程返回子进程的PID:父进程需要管理子进程(如等待子进程),PID是唯一标识符。

PID管理示意图

父进程
└── 子进程1(PID=100)└── 子进程2(PID=101)

3. 写时拷贝(Copy-On-Write, COW)

        父子进程在fork之后,虽然共享代码段和数据段,但在写入时会触发写时拷贝机制。即,当父子进程中的任意一方试图修改共享数据时,系统会为修改方创建一份独立的副本,以避免数据冲突。具体见下图:

内存管理机制

  1. 初始时父子共享物理内存页

  2. 当任一进程尝试写入时触发缺页异常

  3. 内核复制该内存页供修改进程专用

示例验证

int global_val = 100;int main()
{int local_val = 200;pid_t pid = fork();if (pid == 0) {global_val++;local_val++;printf("Child: %d, %d\n", global_val, local_val);} else {sleep(2);  // 确保子进程先执行printf("Parent: %d, %d\n", global_val, local_val);}return 0;
}

运行结果:

4.fork的常规用法

  • 父进程复制自己,使父子进程同时执行不同代码段:例如,父进程等待客户端请求,生成子进程来处理请求。
  • 子进程执行不同的程序:子进程从fork返回后,调用exec函数执行新程序。

5. fork调用失败的原因

  • 系统中已有太多进程。

  • 实际用户的进程数超过了系统限制。

二、进程终止

1.  终止的本质

进程终止时,系统会执行以下操作:

  • 释放代码和数据占用的空间。

  • 释放内核数据结构(如task_struct)。

2. main函数的return返回值

  • main函数的return返回值表示进程的退出状态。

  • 该值会传递给父进程(如Bash shell),父进程可以通过echo $?来获取这个退出状态。

3. 进程退出状态的含义

  • 退出码(Exit Code):

    • 0 表示成功。

    • 非 0 表示失败,具体值可自定义,用于表示不同的失败原因。

  • 退出信号(Exit Signal):

    • 如果进程因接收到信号而终止,退出码可能没有意义。

    • 退出信号可以通过特定方式(如 wait 函数)获取,以判断进程异常原因。

示例分析:

int main() 
{int *ptr = NULL;*ptr = 10;  // 访问空指针,触发段错误(SIGSEGV)return 0;
}

运行时,进程会因段错误被操作系统终止,此时通过 echo $? 获取的值是 139。这是因为 SIGSEGV 的信号编号是 11,而退出状态码是 128 + 11 = 139

4. 父进程为什么会得到子进程的退出码?

父进程需要知道子进程的退出情况,以便:

  • 判断子进程是否成功完成任务。

  • 如果失败,可以通过退出码或信号得知失败原因,从而进行相应的处理(如重试、记录错误日志等)。

5. 异常退出与信号

  • 异常退出原因:

    • 进程做了非法操作,如访问非法内存、除以零等。

  • 信号(Signal):

    • 操作系统会发送一个信号(如 SIGSEGV SIGFPE 等)来终止进程。

    • 退出信号可以用 wait 和相关宏(如 WIFSIGNALEDWTERMSIG)来获取。

6.  进程常见终止情况

  1. 正常终止:

    • main函数返回: return语句的返回值表示进程的退出码。

    • 调用exit函数: 可以在代码的任意位置调用exit终止进程。

    • 调用_exit系统调用: 直接终止进程,不执行清理操作。

  2. 异常终止:

    • 收到操作系统发送的信号(如SIGKILLSIGTERM)。

    • 例如,用户按下Ctrl+C会发送SIGINT信号。

7. exit 和 _exit 的区别

exit系列相关函数:

#include <unistd.h>void exit(int status);        // 调用库函数,执行清理操作后调用_exit
void _exit(int status);       // 系统调用,直接终止进程
  • exit

    • 调用时会执行清理操作,如调用用户注册的清理函数(通过atexiton_exit)、刷新流缓冲区等。

    • 最后调用 _exit 来终止进程。

  • _exit

    • 系统调用,直接终止进程,不执行清理操作。

示例代码:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>void cleanup() 
{printf("Cleanup function called!\n");
}int main() 
{cleanup();  printf("hello");exit(0);  // exit会调用清理函数并刷新缓冲区
}


#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>void cleanup() 
{printf("Cleanup function called!\n");
}int main() 
{cleanup();  printf("hello");_exit(0);  // _exit不会调用清理函数,也不会刷新缓冲区
}

8. return与exit的区别

  • return:

    • 用于从main函数返回,等同于调用exit

    • 返回值会被父进程获取。

  • exit:

    • 显式终止进程,可以指定退出码。

    • 会刷新缓冲区并执行清理操作。

关键字:企业公示信息查询系统四川_网页设计教程课本_百度手机助手下载2021新版_苏州网站排名推广

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: