Linux系统编程---进程相关接口介绍

简述

在日常的开发中,接触的较多可能是多线程的实现。当要实现并行处理时,Linux提供开辟线程和子进程的方式去实现,但从开销上来看,线程是要优于子进程的开辟,但在一些情况下,开辟子进程也是我们去实现功能的首选,

相关接口

1、fork()函数

#include<unistd.h>
pid_t fork(void)
//返回值:子进程返回0,父进程返回子进程ID;出错:返回-1

fork()后,会开辟一个子进程,通过下面的例子,我们可以发现通过对进程描述符的判断,我们可以让子进程实现对应的功能代码。那么子进程在资源分配上与线程有什么不同?

  1. 资源分配
    子进程会与父进程之间共享数据段和代码段,所以父进程中创建的一些文件句柄等系统资源,在子进程中都会被“复制”----共享。共享让资源的使用看起来方便,但在实际开发中,子进程继承父进程的资源时,需要小心去处理(对继承的资源可以选择将其关闭或重新开辟),因为父子进程的相关资源共享使用可能会出现资源竞争的情况。

  2. 资源调度
    Linux为父子进程之间的资源使用----写时复制的策略,那么什么是写时复制呢?

    写时复制是操作系统中对系统资源的一种管理方式。为尽可能的节约资源,当进程之间有共享资源,内核不会将这些资源直接拷贝到这些进程的地址空间中。如果只是读操作,则采取映射的方式去实现,当进程需要对内核进行一个写操作时,内核才会将相关的资源的副本拷贝至对应进程地址空间。

  3. 进程管理
    父进程使用fork()后创建的进程是其的子进程,父子进程的生命周期并不是独立的,这篇博文对父子进程之间的生命周期关系就有很好的描述----linux父子进程问题,所以利用fork()去协助父进程处理相关任务时,就一定要注意资源问题和生命周期的处理。

#include<unistd.h>
#include<iostream>
#include<errno.h>
int main(){
  	pid_t pid;
 	pid = fork();
	int i=0;
 	if(pid<0) {
   		std::cerr<<"fork erro"<<std::endl;
    	exit(1);
 	}
 	 //子进程
  	if(pid == 0){ /*业务逻辑*/}
  	else{ /*业务逻辑*/}
  return 0;
}

2、exit()函数

Linux中提供了一个exit函数,其用处为执行一个进程的退出,在这之前,我们就可以先来了解进程退出的几种状态

正常终止情况:

  1. 正常return
  2. 调用exit
  3. 调用_exit
  4. 进程中的最后一个线程中执行return退出
  5. 进程中最后一个线程调用pthread_exit
    异常状态:
    1.调用abort
    2.当进程接受到某些信号,终止
  6. 最后一个线程收到"取消"信号—取消已延迟发送,线程到时终止。

了解进程退出状态的原因在于,当父进程开辟一个子进程后,他需要知道子进程的一个状态,即时退出,也应即时的告知父进程,这样可以避免当子进程提早结束,父进程不清楚子进程执行情况,从而无法对相关资源进程进行处理,使得子进程成为"僵死进程"(生命周期结束,但资源未释放)。
exit提供了一个参数,在子进程调用exit(num)退出,内核会将这个num传递给父进程。

3、wait()和waitpid

#include<sys/wait.h>
pid_t wait(int *statloc);
pid_t waitpid(pid_t pid,int *statloc,int options);

//成功:返回进程id,出错:返回0
  • wait会阻塞,直到子进程结束,如果子进程已经结束,那么就会直接进行返回。
  • waitpid相对与wait则提供了更多的选择
    • pid:制定的pid对象
    • option:为等待提供选项
    • statloc:存放子进程的退出信息
#include<iostream>
#include<sys/wait.h>
#include<unistd.h>
#include<errno.h>
int main(){
  pid_t pid;
  int status;
  if((pid = fork())<0)
    std::cerr<<"fork1 erro:"<<std::endl;
  else if(pid==0){
    std::cout<<"I am Child1"<<std::endl;
    exit(1);
  }
  else{
    wait(&status);
    std::cout<<"child exit:"<<status<<std::endl;
  }
  return 0;
}
exit(1)时
wlm@wlm:~/code/example/Linux$ ./exit
I am Child1
child exit:512
exit(2)时
wlm@wlm:~/code/example/Linux$ ./exit
I am Child1
child exit:512

从上面的例子我们可以看出,exit的退出码,是可以通过wait来捕捉的,(关于退出码的解读,我这里也没搞弄很明白,若有了解的网友可评论留言-在书中,说了wait及waitpid会获得的终止状态的宏,我的疑惑在于:exit的返回的终止码可以自定义指定,那么内核如何去将这些宏与自定义的终止码去对应?还是说,exit的退出码是有规定的?)

对于waitpid的pid

pid参数
pid==-1等待任一子进程,此种情况下,waitpid和wait等效
pid>0等待进程ID与pid相等的子进程
pid==0等待调用进程组内的任一进程退出
pid<-1等待组id等于pid绝对值的任一子进程

4、waitid()函数

#include<sys/wait.h>
int waitid(idtype_t idtype,id_t id,siginfo_t *info,int option);
//成功返回0,失败返回-1

wait()、waitpid()及waitid()介绍

相比于之前的waitid函数,使用waitid的灵活性更高,关于idtype和option的设定可以参见上文的链接,另外waitid还提供了一个siginfo_t类型变量,这个变量可以获取子线程的信号相关信息。

5、exec()函数

链接中对exec进行了详细的描述----exec函数详解

前面使用fork可以开辟一块空间执行子进程代码,但实并不是所有情况fork都能满足,当需要使用其他应用程序,我们可以通过fork先向系统申请资源空间,然后在新开辟的空间中,使用exec来运行一个新的程序,从而实现多进程。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值