愿我们都能成为
一个童心未泯的大人,不被世俗化,不被规则化~
目录:
- 每日总结
- 掌握fork/vfork函数的使用
- 熟练掌握wait的函数使用
- popen/system两个函数和fork的区别
>>1.每日总结
1.程序和进程
程序:二进制文件,占用的磁盘空间;
进程:启动的程序;所有的数据都在内存中;需要占用更多的系统资源;(cpu,物理内存)
2.并发和并行
并发:时间段的概念。
并行:增加处理器并行处理。(例如:淘宝,12306购票)
3.pcb:进程控制块
- 进程id。系统中每个唯一的id,在C语言中用pid_t 类型的表示,其实就是一个非负整数;
- 进程的状态:就绪,运行,挂起,停止等;
- 进程切换时需要保存和恢复的一些CPU寄存器;
- 描述虚拟地址空间的信息;
- 描述控制终端的信息;
- umask掩码;
- 文件描述符,包含很多指向file结构体指针;
- 用户id和组id;
- 多个进程形成进程组;
>>2.fork/vfork函数及其实现
- 相似Linux中fork函数是非常重要的,它从已经存在的进程中创建一个新进程。新进程为子进程,而原进程为父进程;
- fork函数:通过复制调用进程创建一个新的子进程;
- fork函数的返回值:子进程返回1;父进程返回的是子进程的pid;
- vfork函数:创建子进程,与父进程共用同一个虚拟地址空间;
- fork/vfork函数在内核中创建进程都是调用clone函数实现pcb创建并拷贝数据的。
结果演示:
>>wait函数的实现(进程等待)
- 子进程退出,父进程如果不管不顾,就可能造成“僵尸进程”的问题,进而造成内存泄漏;
- 进程一旦成为“僵尸进程”,那么就“刀枪不入”,就连kill -9也无能为力,没有办法杀死一个已经死去的进程;
- 父进程通过进程等待的方式,回收子进程资源,获取子进程退出的信息。
- wait函数的返回值:成功返回被等待的进程pid;失败返回-1;
- wait函数参数:输出类型参数,获取子进程退出状态,不关心则可以设置为NULL。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/wait.h>
int main()
{
int pid = fork();
if (pid < 0) {
//errno是一个全局变量,存储每次系统调用出现错误原因编号
//strerror,通过错误编号获取字符串错误原因
printf("fork error :%s\n", strerror(errno));
//perror直接打印上一个系统调用错误原因
perror("fork error");
}else if(pid == 0) {
sleep(3);
exit(257);
}
//pid_t wait(int *status);
//阻塞等待任意一个子进程退出,获取返回值
//wait(NULL);
//pid_t waitpid(pid_t pid, int *status, int options);
//阻塞等待任意一个子进程或者指定的子进程退出
//pid: -1:等待任意一个子进程 pid>0:等待指定子进程
//options: WNOHANG:将waitpid设置为非阻塞 0:默认阻塞
//返回值:若WNOHANG被指定,没有子进程退出则立即报错返回0;错误:-1
int statu;
while(waitpid(-1, &statu, WNOHANG) == 0) {
//非阻塞轮询操作
printf("drink coffee\n");
sleep(1);
}
if ((statu & 0x7f) == 0){
printf("exit code:%d\n", (statu >> 8) & 0xff);
}
if (WIFEXITED(statu)) {
printf("exit code:%d\n", WEXITSTATUS(statu));
}
while(1) {
printf("i am parent\n");
sleep(1);
}
return 0;
}
结果演示:
>>popen/system
system:在执行期间调用进程会一直等待shell命令执行完成
popen:无须等待shell命令执行完成就返回 (并行执行)
popen后需要调用pclose防止子进程变成”僵尸”状态。
fork :执行期间父进程等待子进程的退出码
system:对SIGCHLD、SIGINT、SIGQUIT都做了处理,
system()调用堆信号屏蔽的原因是因为system能够及时的退出
并且能够正确的获取子进程的退出状态(成功回收子进程)。
popen:没有对信号做任何的处理。
popen()函数中没有屏蔽SIGINT、SIGQUIT的原因
是因为popen是”并行的”,不能影响其它”并行”进程。
system:执行shell命令最后返回是否执行成功,
popen:执行命令并且通过管道和shell命令进行通信。
在特权(setuid、setgid)进程中千万注意不要使用system和popen这两个函数!
~bye
~