8、进程控制(1)
来源:互联网 发布:知乎笔记本推荐 编辑:程序博客网 时间:2024/06/14 15:11
1、进程ID总是唯一的,常将其作为其他标识符的一部分以确保其唯一性。一个进程结束后ID可以复用,一般采用延迟复用法。ID为0是调度进程(交换进程),是内核的一部分属于系统进程。ID=1是init进程,在内核自举后启动UNIX系统,他通常读取与系统相关的初始化文件(/etc/rc*,/etc/inittab,/etc/init.d中文件等)。init进程不会停止,虽然是普通进程却是以root权限允许。
#include <unistd.h>pid_t getpid(void);pid_t getppid(void);//返回父进程IDuid_t getuid(void);uid_t geteuid(void);//返回调用进程的有效用户IDgid_t getgid(void);gid_t getegid(void);
2、fork
子进程是父进程的副本,子进程获得父进程数据空间、堆、栈的副本,共享正文段。子进程和父进程都会继续执行fork之后的部分。fork之后子进程先执行还父进程先执行取决于调度算法。
int globvar=6;char buf[]="a write to stdout\n";int main(void){ int var; pid_t pid; var = 88; //strlen不包含终止null字节,需要进行一次函数调用 //sizeof计算包含终止null的长度,sizeof是在编译时计算缓冲区长度。 if(write(STDOUT_FILENO, buf, sizeof(buf)-1) != sizeof(buf)-1) err_sys("write error"); printf("before fork\n"); if((pid = fork()) < 0){ err_sys("fork error"); }else if(pid == 0){ globvar++; var++; }else{ sleep(2); } printf("pid=%ld,glob=%d,var=%d\n",(long)getpid(),globvar,var); exit(0);}
//标准输出连到终端设备,只得到一次printf输出,因为缓冲区由换行符冲洗$ ./myforka write to stdoutbefore forkpid=2114,glob=7,var=89pid=2113,glob=6,var=88//当输出重定向到一个文件,printf输出2次,因为fork时缓冲区数据也被复制到子进程。每个进程终止时缓冲区输出到各文件。$ ./myfork >temp$ cat tempa write to stdoutbefore forkpid=2116,glob=7,var=89before forkpid=2115,glob=6,var=88
fork父进程和子进程共享一个文件偏移量,文件表项位于内核
3、vfork
vfork在调用exec或exit之前和父进程在相同空间(父进程空间,不复制地址空间)运行。vfork保证子进程先运行,调用exec或exit后父进程才可能运行。
4、exit,_exit由exit调用,_exit是系统调用,exit是C库函数
内核为每个终止子进程保存一定量的信息,当其父进程调用wait或waitpid时可以得到这些信息。
僵尸进程:一个进程已经终止,但是其父进程没有做善后操作(获取终止进程的相关信息,释放它仍占用的资源)。
一个进程的父进程先于子进程终止,则子进程的父进程变为init(收养)。只要init进程的一个子进程终止,它就会调用一个wait函数取得其终止状态。
5、父进程执行wait和waitpid
一般有进程终止时内核向其父进程发送SIGCHLD信号,父进程再调用wait/waitpid。所有子进程都还在运行则阻塞;一个进程已终止则得到其终止状态并返回;没有任何子进程则出错返回。
#include <sys/wait.h>//返回第一个终止的子进程ID,子进程信息存于statlocpid_t wait(int *statloc);//等待特定子进程pid_t waitpid(pid_t pid, int *sataloc, int options);
//父进程先终止,子进程的父进程变为init(ID=1)#include "apue.h"#include <sys/wait.h>int main(){ pid_t pid; if((pid = fork()) < 0) err_sys("fork error"); else if(pid == 0){ if((pid = fork()) < 0) err_sys("fork error"); else if(pid > 0) exit(0); sleep(2); printf("second child,parent pid=%ld\n",(long)getppid()); exit(0); } if(waitpid(pid, NULL, 0) != pid) err_sys("waitpid error"); exit(0);}
6、exec
调用exec函数使新进程执行另一个程序。该新程序从一个新文件的main处开始执行(用磁盘上的一个新程序替代了当前进程的正文段、数据段、堆段、栈段)。如果找到的非可执行文件,而是一个shell脚本则调用/bin/sh
linux中只有execve是内核的系统调用,其他6个都是库函数
#include <unistd.h>//l代表参数列表,v代表参数矢量(数组),e代表环境变量//p代表第一个参数为文件名,在PATH路径中寻找//f开头表示第一个参数为文件标识符int execl(const char *pathname, const char *arg0,...);int execv(const char *pathname, const char *arg[]);int execle(const char *pathname, const char *arg0,..., char *const envp[]);int execve(const char *pathname, const char *arg[], char *const envp[]);int execlp(const char *filename, const char *arg0,...);int execvp(const char *filename, const char *arg[]);int fexecve(int fd, const char *arg[], char *const envp[]);
//在对应目录中分别编译两个文件//exec调用的是可执行文件#include "apue.h"#include <sys/wait.h>char *env_init[] = {"USER=unknown", "PATHA=/temp", NULL};int main(void){ pid_t pid; if((pid = fork()) < 0){ err_sys("fork error"); }else if(pid == 0){ if(execle("/home/john/temp/echoall", "echoall", "myarg1", "MYARG2", (char *)0, env_init) < 0) err_sys("execle error"); } if(waitpid(pid, NULL, 0) < 0) err_sys("wait error"); if((pid = fork()) < 0){ err_sys("fork error"); }else if(pid == 0){ //execlp在PATH寻找该文件 if(execlp("echoall", "echoall", "only 1 arg", "MYARG2", (char *)0) < 0) err_sys("execlp error"); } exit(0);}
int main(int argc, char *argv[]){ int i; char **ptr; extern char **environ; for(i = 0; i < argc; i++) printf("argv[%d]: %s\n", i, argv[i]); for(ptr = environ; *ptr != 0; ptr++) printf("%s\n", *ptr); exit(0);}
- 8、进程控制(1)
- APUE(8) ---- 进程控制(1)
- 进程控制(二)进程控制编程
- Linux下进程描述(1)—进程控制块
- 8进程控制
- 专题 8 进程控制
- Chapter 8 进程控制
- 8(进程控制)
- 8章 进程控制
- Linux编程之进程控制(1)
- apue第八章 进程控制 (1)
- 进程控制开发-1
- 进程控制1之初识进程
- 进程控制-进程创建(fork、vfork)
- 进程控制-进程终止(exit、_exit)
- 第8章 进程控制
- 第8章 进程控制
- 第8章 进程控制
- newoj 3311: Mixing Milk 混合牛奶
- Cg Programming/Vertex Transformations Cg编程/顶点变换
- spring4.x系列学习笔记(四)
- Linux-4.9.2内核在mini2440上的移植(八)——RTC驱动移植
- 模拟三次密码输入的场景
- 8、进程控制(1)
- 第二单元
- 短信在用户运营中的使用
- hdu3530(单调队列)
- STL-list支持的集中常见操作的用法
- Linux系统常用命令回顾
- MPAndroidChart
- Longest Common Prefix
- 常见算法基础题思路简析(三)-二叉树篇