Linux多进程

本文介绍了Linux进程的基本概念,如进程ID的获取方法,特殊进程如idle、systemd和内核进程kthreadd,以及fork函数的使用。重点讲解了孤儿进程和僵尸进程的形成及解决策略。
摘要由CSDN通过智能技术生成

1. 标识

每个进程都有一个非负整数表示的唯一进程ID。

查看进程命令:        ps -ef | grep 进程名

代码获取进程id

getpid(void)                获取进程id

getppid(void)              获取父进程id

#include <iostream>
#include <unistd.h>

using namespace std;
int main(){
	cout << getpid() << endl;
	cout << getppid() << endl;
	sleep(100);
}

2. 特殊进程

idle进程

  • pid为0
  • linux系统中的第一个进程,加载完成之后演变成1、2号进程
  • 是init进程和kthreadd进程的父进程

systemd(init)进程

  • pid为1
  • linux中第一个用户空间的进程
  • 系统初始化,是其他用户空间进程的直接或间接父进程

kthreadd进程

  • pid为2
  • 内核空间其他进程的直接或间接父进程
  • 负责内核线程的调度和管理

3. fork函数

  • 一个现有的进程调用fork函数会创建一个新的进程
  • 子进程和父进程继续执行fork函数后的代码
  • fork函数调用一次,返回两次
  • 子进程返回0,父进程返回子进程的进程id
  • 子进程是父进程的副本
  • 子进程获得了父进程的数据空间、堆和栈的副本,不是共享
  • 一般会执行成功,如果内存不足或资源不够,执行失败时返回-1
  • 父进程中打开的文件描述符也被复制到子进程中,子父进程可以同时向文件写入数据。如果在子进程中关闭文件,父进程不受影响,可以继续写,关闭父进程中的文件,子进程也可以继续写文件,不受影响。

代码

#include <iostream>
#include <unistd.h>
using namespace std;

int main(){

  int pid = fork();

  if(pid > 0) {
    cout << "this is parent, pid=" << getpid() << endl;
    sleep(20);
  } else {
    cout << "this is child, pid=" << getpid() << endl;
    sleep(20);
  }

}

4. 孤儿进程

如果父进程先退出,子进程会成为孤儿进程,将被1号进程收养,由1号进程对他们完成状态收集工作。

孤儿进程没有危害。

#include <iostream>
#include <unistd.h>
using namespace std;

int main(){

  int pid = fork();

  if(pid > 0) {
    cout << "this is parent, pid=" << getpid() << endl;
    sleep(10);
  } else {
    cout << "this is child, pid=" << getpid() << endl;
    sleep(20);
  }

}

父进程睡眠10秒

5. 僵尸进程

如果子进程先退出,内核向父进程发送SIGCHLD信号,如果父进程不处理这个信号,子进程就会成为僵尸进程。

僵尸进程的危害

如果子进程在父进程之前终止,内核为每个子进程保留了一个数据结构,包括进程编号、终止状态和使用cpu时间等。父进程如果处理了子进程退出的信息,内核就会释放这个数据结构。如果父进程没有处理子进程退出的信息,内核就不会释放这个数据结构,子进程编号就会一直被占用,但是系统可用的进程号是有限的。如果大量的产生僵尸进程,将因为没有可用的进程号而导致系统不能产生新的进程

#include <iostream>
#include <unistd.h>

using namespace std;
int main(){

  int pid = fork();
  if(pid == 0) {
    cout << "this is child , pid=" << getpid() << endl;
    sleep(10);
  } else {
    cout << "this is parent, pid=" << getpid() << endl;
    sleep(30);
  }
  return 0;
}

运行结果:

[fork01] <defunct> 表示僵尸进程。

解决僵尸进程的三种方式:

1. 父进程中忽略SIGCHLD信号

#include <iostream>
#include <unistd.h>
#include <signal.h>

using namespace std;
int main(){
  // 忽略SIGCHLD信号
  signal(SIGCHLD, SIG_IGN);

  int pid = fork();
  if(pid == 0) {
    cout << "this is child , pid=" << getpid() << endl;
    sleep(10);
  } else {
    cout << "this is parent, pid=" << getpid() << endl;
    sleep(30);
  }
  return 0;
}

十秒以后,子进程退出。

2. 在父进程中增加等待子进程退出的代码

#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>

using namespace std;
int main(){

  int pid = fork();
  if(pid == 0) {
    cout << "this is child , pid=" << getpid() << endl;
    sleep(10);
  } else {
    cout << "this is parent, pid=" << getpid() << endl;
    int sts;
    wait(&sts);
    sleep(30);
  }
  return 0;
}

wat函数会阻塞父进程的执行,等待子进程退出。

3. 设置SIGCHLD信号的处理函数,在处理函数中调用wait函数

#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>

using namespace std;

void func(int sig){
  int sts;
  wait(&sts);
}



int main(){

  // 设置信号处理函数
  signal(SIGCHLD, func);

  int pid = fork();
  if(pid == 0) {
    cout << "this is child , pid=" << getpid() << endl;
    sleep(10);
  } else {
    cout << "this is parent, pid=" << getpid() << endl;
    sleep(30);
  }
  return 0;
}

休眠10秒后,父子进程会一起退出,原因是子进程运行10秒钟后退出,然后内核给父进程发了一个SIGCHLD信号,该信号是软中断信号,会中断父进程的sleep的调用,然后进入func函数,执行完func函数,程序就退出了,可以sleep两次来解决这个问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值