C++学习笔记(43)

五、共享文件

fork()的一个特性是在父进程中打开的文件描述符都会被复制到子进程中,父进程和子进程共享同一

个文件偏移量。

如果父进程和子进程写同一描述符指向的文件,但又没有任何形式的同步,那么它们的输出可能会相

互混合。

示例:

#include <iostream>

#include <fstream>

#include <unistd.h>

using namespace std;

int main()

{

ofstream fout;

fout.open("/tmp/tmp.txt"); // 打开文件。

fork();

for (int ii=0;ii<10000000;ii++) // 向文件中写入一千万行数据。

{

fout << "进程" << getpid() << "西施" << ii << "极漂亮" << "\n"; // 写入的

内容无所谓。

}

fout.close(); // 关闭文件。

}

六、vfork()函数

vfork()函数的调用和返回值与 fork()相同,但两者的语义不同。

vfork()函数用于创建一个新进程,而该新进程的目的是 exec 一个新程序,它不复制父进程的地址空

间,因为子进程会立即调用 exec,于是也就不会使用父进程的地址空间。如果子进程使用了父进程的地

址空间,可能会带来未知的结果。

vfork()和 fork()的另一个区别是:vfork()保证子进程先运行,在子进程调用 exec 或 exit()之后父进

程才恢复运行。

316、僵尸进程

如果父进程比子进程先退出,子进程将被 1 号进程托管(这也是一种让程序在后台运行的方法)。

如果子进程比父进程先退出,而父进程没有处理子进程退出的信息,那么,子进程将成为僵尸进程。

僵尸进程有什么危害?内核为每个子进程保留了一个数据结构,包括进程编号、终止状态、使用 CP

U 时间等。父进程如果处理了子进程退出的信息,内核就会释放这个数据结构,父进程如果没有处理子进

程退出的信息,内核就不会释放这个数据结构,子进程的进程编号将一直被占用。系统可用的进程编号是

有限的,如果产生了大量的僵尸进程,将因为没有可用的进程编号而导致系统不能产生新的进程。

僵尸进程的避免:

1)子进程退出的时候,内核会向父进程发头 SIGCHLD 信号,如果父进程用 signal(SIGCHLD,SIG_I

GN)通知内核,表示自己对子进程的退出不感兴趣,那么子进程退出后会立即释放数据结构。

2)父进程通过 wait()/waitpid()等函数等待子进程结束,在子进程退出之前,父进程将被阻塞待。

pid_t wait(int *stat_loc);

pid_t waitpid(pid_t pid, int *stat_loc, int options);

pid_t wait3(int *status, int options, struct rusage *rusage);

pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage);

返回值是子进程的编号。

stat_loc 是子进程终止的信息:a)如果是正常终止,宏 WIFEXITED(stat_loc)返回真,宏 WEXITST

ATUS(stat_loc)可获取终止状态;b)如果是异常终止,宏 WTERMSIG(stat_loc)可获取终止进程的信号。

3)如果父进程很忙,可以捕获 SIGCHLD 信号,在信号处理函数中调用 wait()/waitpid()。

示例一:

#include <iostream>

#include <unistd.h>

#include <sys/types.h>

#include <sys/wait.h>

using namespace std;

int main()

{

if (fork()>0)

{ // 父进程的流程。

int sts;

pid_t pid=wait(&sts);

cout << "已终止的子进程编号是:" << pid << endl;

if (WIFEXITED(sts)) { cout << "子进程是正常退出的,退出状态是:" << WEXITSTATUS(sts)

<< endl; }

else { cout << "子进程是异常退出的,终止它的信号是:" << WTERMSIG(sts) << endl; }

}

else

{ // 子进程的流程。

//sleep(100);

int *p=0; *p=10;

exit(1);

}

}

示例二:

#include <iostream>

#include <unistd.h>

#include <sys/types.h>

#include <sys/wait.h>

using namespace std;

void func(int sig) // 子进程退出的信号处理函数。

{

int sts;

pid_t pid=wait(&sts);

cout << "已终止的子进程编号是:" << pid << endl;

if (WIFEXITED(sts)) { cout << "子进程是正常退出的,退出状态是:" << WEXITSTATUS(sts) <<

endl; }

else { cout << "子进程是异常退出的,终止它的信号是:" << WTERMSIG(sts) << endl; }

}

int main()

{

signal(SIGCHLD,func); // 捕获子进程退出的信号。

if (fork()>0)

{ // 父进程的流程。

while (true)

{

cout << "父进程忙着执行任务。\n";

sleep(1);

}

}

else

{ // 子进程的流程。

sleep(5);

// int *p=0; *p=10;

exit(1);

}

}

317、多进程与信号

在多进程的服务程序中,如果子进程收到退出信号,子进程自行退出,如果父进程收到退出信号,则

应该先向全部的子进程发送退出信号,然后自己再退出。

示例:

#include <iostream>

#include <unistd.h>

#include <signal.h>

using namespace std;

void FathEXIT(int sig); // 父进程的信号处理函数。

void ChldEXIT(int sig); // 子进程的信号处理函数。

int main()

{

// 忽略全部的信号,不希望被打扰。

for (int ii=1;ii<=64;ii++) signal(ii,SIG_IGN);

// 设置信号,在 shell 状态下可用 "kill 进程号" 或 "Ctrl+c" 正常终止些进程

// 但请不要用 "kill -9 +进程号" 强行终止

signal(SIGTERM,FathEXIT); signal(SIGINT,FathEXIT); // SIGTERM 15 SIGINT 2

while (true)

{

if (fork()>0) // 父进程的流程。

{

sleep(5); continue;

}

else // 子进程的流程。

{

// 子进程需要重新设置信号。

signal(SIGTERM,ChldEXIT); // 子进程的退出函数与父进程不一样。

signal(SIGINT ,SIG_IGN); // 子进程不需要捕获 SIGINT 信号。

while (true)

{

cout << "子进程" << getpid() << "正在运行中。\n"; sleep(3); continue;

}

}

}

}

// 父进程的信号处理函数。

void FathEXIT(int sig)

{

// 以下代码是为了防止信号处理函数在执行的过程中再次被信号中断。

signal(SIGINT,SIG_IGN); signal(SIGTERM,SIG_IGN);

cout << "父进程退出,sig=" << sig << endl;

kill(0,SIGTERM); // 向全部的子进程发送 15 的信号,通知它们退出。

// 在这里增加释放资源的代码(全局的资源)。

exit(0);

}

// 子进程的信号处理函数。

void ChldEXIT(int sig)

{

// 以下代码是为了防止信号处理函数在执行的过程中再次被信号中断。

signal(SIGINT,SIG_IGN); signal(SIGTERM,SIG_IGN);

cout << "子进程" << getpid() << "退出,sig=" << sig << endl;

// 在这里增加释放资源的代码(只释放子进程的资源)。

exit(0);

}

相关推荐
张铁铁是个小胖子10 分钟前
微服务学习
java·学习·微服务
AITIME论道1 小时前
论文解读 | EMNLP2024 一种用于大语言模型版本更新的学习率路径切换训练范式
人工智能·深度学习·学习·机器学习·语言模型
编程之路,妙趣横生2 小时前
list模拟实现
c++
明明真系叻2 小时前
第二十六周机器学习笔记:PINN求正反解求PDE文献阅读——正问题
人工智能·笔记·深度学习·机器学习·1024程序员节
青春男大4 小时前
java栈--数据结构
java·开发语言·数据结构·学习·eclipse
一只小bit4 小时前
数据结构之栈,队列,树
c语言·开发语言·数据结构·c++
mashagua5 小时前
RPA系列-uipath 学习笔记3
笔记·学习·rpa
nikoni235 小时前
828考研资料汇总
笔记·其他·硬件工程
沐泽Mu5 小时前
嵌入式学习-QT-Day05
开发语言·c++·qt·学习
锦亦之22335 小时前
cesium入门学习二
学习·html