【Linux系统编程】——进程控制
目录
进程控制
1、进程标识
2、函数fork
3、函数exit
4、函数wait和waitpid
5、函数waitid
6、wait3和wait4
7、竞争条件
8、函数exec
9、函数system
进程控制
1、进程标识
- 若要对进行相关操作时,那么需要获取相关进程的标识信息。一般情况下,获取本身的pid即可
pid_t getpid(void); //返回进程的进程ID
pid_t getppid(void); //返回父进程id
2、函数fork
pid_t fork(void); //返回值:子进程返回0,父进程返回子进程ID,若出错,返回-1
- 调用fork,系统会为调用者创建一个子进程,该子进程会复制其父进程的所有内容(对于一些指针,空间管理时应当注意这一点)。子进程与父进程对空间的分配策略为“写时复制”,即当不对父进程空间内容进行修改,父与子共享该块空间,当双方中的任何一方对内容进行修改,则重新拷贝一份到自己的空间中进行修改。
3、函数exit
- 调用exit,函数则会停止执行,并调用终止处理程序(关于终止处理程序,也是Linux提供的函数,当函数结束时,可进行执行)。
4、函数wait和waitpid
#include<sys/wait.h>
pid_t wait(int *statloc); //statloc会存放子进程的终止状态信息。
pid_t waitpid(pid_t pid,int *statloc,int options);
//若成功返回进程ID,若出错,返回0或-1
- 这两个函数,主要针对子进程与父进程之间的生命周期不同而产生问题的解决。
- wait会使调用者阻塞(父进程),直到其子进程结束。当父进程有多个子进程进行等待,那么只要有一个子进程返回则会响应
- waitpid相对于wait功能更加丰富,可以通过参数来进行设置
-
关于pid的设置
pid==-1----> 等待任一子进程
pid>0------> 等待进程ID与pid相等的子进程
pid==0-----> 等待ID等于调用进程组ID的任一子进程
pid<-1-----> 等待组ID等于pid绝对值的任一子进程 -
关于options的设置
WNOHANG----> 若由pid指定的子进程并不是立即可用的,则waitpid不阻塞,此时其返回值为0
-
5、函数waitid
#include<sys/wait.h>
int waitid(idtype idtype, id_t id,siginfo_t *inforp,int options);
//返回值:若成功,返回0;若出错,返回-1;
- waitid相对之前的两个函数,又提供了对子进程等待的自定义操作。
-
idtype的设置
P_PID -----> 等待一特定进程(id)
P_PGID -----> 等待特定进程组(id)的任一子进程
P_ALL ------> 等待任一子进程:忽略id -
options参数,该参数可以进行位或运算
WCONTINUED ----> 等待一进程,它以前曾被停止,此后又继续,但其状态尚未报告
WEXITED -------> 等待已退出的进程
WNOHANG -------> 如无可用的子进程退出状态,立即返回而非阻塞
WNOWAIT -------> 不破坏子进程退出状态,该子进程退出状态可由后续的wait、waitid等调用取得
WSTOPPED ------> 等待一进程,它已经停止,但其状态尚未报告 -
WCONTINUED,WEXITED,WSTOPPED三者之一必须被指定。
-
6、wait3和wait4
- 这两个函数的则是接收子进程结束信息时,对其使用资源进行统计。
7、竞争条件
- 父进程创建子进程,如果父子进程需要协同工作时,就需要注意相关的竞争条件,这种情况就类似多线程的资源安全问题,那么就需要对父进程和子进程的执行上设置条件,一种方法是轮询等待。但是针对这种进程中的共享资源或是协同工作的问题,文中建议使用信号量来进行操作。
8、函数exec
- 父进程调用fork可以开辟一个子进程,一般情况下子进程会共享父进程空间。Linux提供了exec函数用于在子进程中允许其他函数,使得子进程空间被替换成指定"进程"得空间。
#include<unistd.h>
int execl(const char *pathname,const char *arg0,....);
int execv(const char *pathname,char *const argv[]);
int execlp(const char *filename,const char *arg0,...);
int execvp(const char *filename,char *const argv[]);
//filename:文件名
//pathname:路径名
//arg0:参数0,多个参数下,可以一一设置
//argv[]:将参数形成字符串进行传递
- 以上函数不能在父进程空间中直接开辟,而是要通过先开辟一个子进程,在子进程中进行调用。
#include<unistd.h>
#include<sys/wait.h>
int main(){
pid_t pid;
if((pid = fork())<0){
perro("fork erro\n");
}else if(pid == 0){
if(execl(...,...)<0){
perro("ececl erro\n");
}
}
}
- 在子进程中创建一个新的程序,新进程会继承父进程得相关进程信息,若在使用中需要请自行查阅手册。
9、函数system
- 在函数如果要执行命令,则调用system即可。实际上system执行命令(实际上也是程序)时,也是利用得开辟子进程得方式,来实现命令的执行
#include<stdlib.h>
int system(const char *cmdstring);
- 关于system的具体实现
#include<sys/waith>
#include<errno.h>
#include<unistd.h>
int system(const char *cmdstring){
pid_t pid;
int status;
if(cmdstring == NULL)
return 1;
if((pid==fork())<0){
status = -1;
}else if(pid==0){
execl(...,...);
_exit(127);
}else{
//父进程在这里进行了简单安全性的检测
while(waitpid(pid,&status,0)<0){
if(errno!=ENTER){
status = -1;
break;
}
}
}
}
- ps:以上是博主认为在开发过程中一般会使用到的函数,遂收集整理。若有不足,请网友留言指正。

浙公网安备 33010602011771号