进程控制块PCB
- 进程id:系统中每个进程有唯一的id,在c语言中用pid_t 表示,其实就是非负整数
- 进程的状态:就绪,运行,挂起,停止,僵尸等状态
- 进程切换是需要保存和恢复的一些cpu寄存器
- 描述虚拟地址空间的信息
- 描述控制终端的信息
- 当前工作目录
- umask掩码
- 文件描述符表,包含很多指向file 结构体的指针
- 信号相关信息
- 用户id和组id
- 控制终端,session和进程组
- 进程可以使用的资源上限
进程控制fork
fork的作用是根据一个现有的进程辅助出一个新进程,原来的进程称为父进程,新进程称为子进程。系统中同时运行着很多的进程,这些进程都是从最初只有一个进程开始一个一个复制出来的。
在shell下输入命令可以运行一个程序,是因为shell进程在读取用户输入的命令之后会调用fork复制出一个新的shell进程。
fork 代码实例
int main() {
std::string msg;
int n;
pid_t pid = fork();
if(pid < 0){
perror("fork");
exit(1);
}
if(pid == 0){
// 子进程
msg = "child process~\n";
n = 6;
}else{
// 父进程
msg = "parent process~\n";
n = 3;
}
while (n> 0){
std::cout << msg;
sleep(1);
n--;
}
return 0;
}
上面程序,当pid == 0 时,就是子进程执行逻辑,不等于0的时候就是父进程的代码执行逻辑。
上面的小程序运行结果是:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sBQoTOnI-1686839557283)(null)]
可以发现上面的结果中有bash 进程的参与。这是因为父进程在3s后就死掉了,然后子进程就成了孤儿进程。他会给另一个进程去托管。其实上面的进程关系是bash->parent->child 。当parent死掉后,bash进程作为他的父进程会恢复自己的状态 。我们再将程序改动一下,打印一下,各个进程的pid,来看看最后作为孤儿进程的child process 被哪个进程托管了。
getPid + getPPid
int main() {
std::string msg;
int n;
pid_t pid = fork();
if(pid < 0){
perror("fork");
exit(1);
}
if(pid == 0){
// 子进程
n = 6;
while(n > 0){
std::cout << "self child pid = " << getpid() << "parent pid = " << getppid() << std::endl;
sleep(1);
n--;
}
}else{
// 父进程
n = 3;
while(n > 0){
std::cout << "self parent pid = " << getpid() << "parent pid = " << getppid() << std::endl;
sleep(1);
n --;
}
}
return 0;
}
上面的结果可以看出 后面的孤儿进程 被 pid 为 1的系统的第一个进程给接管了。