【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:以上是博主认为在开发过程中一般会使用到的函数,遂收集整理。若有不足,请网友留言指正。
    posted @ 2020-03-01 21:19  王磊明  阅读(185)  评论(0)    收藏  举报