- Linux下进程控制函数
- 重要的进程函数
- 获取进程ID
- 创建与终止进程
- 创建进程
- 终止进程
- 回收子进程
- options参数
- status参数
- 错误条件
- 代码演示
- wait函数
- 让进程休眠
- sleep函数
- pause函数
- 加载并运行新的程序
- 环境变量相关函数
- 利用进程控制接口,编写简单的shell程序
#include创建与终止进程 创建进程#include pid_t getpid(void) //返回调用进程的ID pid_t getppid(void) //返回父进程的ID
#include#include pid_t fork(void)
fork出来的进程会获得与父进程用户级虚拟地址空间相同(但是独立)的一份副本,但是PID不同。
fork是一个有趣但令人迷惑的函数,它只被调用一次,但是会返回两次,一次在父进程中,一次在子进程中。在父进程中会返回子进程的pid(非零),在子进程中会返回0,因此可以以此来区分是程序是在子进程中执行还是在父进程中执行。
int main(){
pid_t pid;
int x = 1;
pid = Fork();//fork的包装函数
if(pid == 0){
printf("child : x=%d n",++x);
exit(0);
}
printf("parent:x=%dn",--x);
exit(0);
}
获得输出:
parent:x=0 child:x=2
从结果看出父子进程并不共享数据x,但是共享文件,因为都把输出打到了标志输出stdout上。
终止进程#include回收子进程void exit(int status);
僵死进程(zombie process)
终止但未被回收的进程被称为僵尸进程。当一个进程由于某中原因被终止时,内核并不会立刻把它从系统中清除,它会被保持在一种已终止的状态,直到被它的父进程回收。
如果一个僵死进程在被回收之前,父进程就已经结束,那么内核会安排init进程来回收,init进程的pid为1,是所有进程的祖先。
一个进程可以通过调用waitpid函数来等待它的子进程终止:
#includeoptions参数#include pid_t waitpid(pid_t pid,int *statusp,int options)
waitpid中options参数对行为的影响:
| options | 行为 |
|---|---|
| 0(默认) | 挂起调用线程,若此时pid>0,则等待对应pid的子进程结束,若此时pid=-1,则等待任一子进程结束 |
| WNOHANG | 不等待子进程结束,立即返回,若此时返回值为0,表示没有子进程结束 |
| WUNTRACED | 挂起调用线程,直到任一子线程终止或者被停止,注意与默认值0的区别为,默认值只返回正常终止的子进程 |
| WCONTINUED | 挂起调用线程,直到任一子线程终止,或者任一一个被停止的子线程收到SIGCONT信号重新开始执行 |
注意options的参数可以进行组合,比如WNOHANG | WUNTRACED。
status参数| status值 | 含义 |
|---|---|
| WIFEXITED(status) | 如果子进程通过exit或者return返回,则为真 |
| WEXITSTATUS(status) | 返回一个正常终止的子进程的退出状态,只有在WIFEXITED(status)为真时,才会定义这个状态 |
| WIFSIGNALED(status) | 如果子进程是因为一个未被捕获的信号终止的,那么就返回真 |
| WTERMSIG(status) | 返回导致子进程终止的信号编号,只有当WIFSIGNALED(status)为真时,才定义这个信号 |
| WIFSTOPPED(status) | 如果引起返回的子进程当前是停止的,那么久返回真 |
| WSTOPSIG(status) | 返回引起子进程停止的信号的编号。只有在WIFSTOPPED()返回为真时,才定义这个状态 |
| WIFCONTINUED(status) | 如果子进程收到SIGCONT信号重新启动,则返回真 |
如果调用进程没有子进程,waitpid返回-1,并且设置errorno为ECHILD,
如果waitpid函数被一个信号中断,返回-1,设置errorno为EINTR。
#include#include #include #include #include int main(){ int status,i; const int N = 10; pid_t pid; for(i = 0; i < N;++i){ if(fork() == 0){ printf("It's child n"); exit(100+i); } } while((pid = waitpid(-1,&status,0)) > 0){ if(WIFEXITED(status)) printf("child %d terminate normally with exit status = %dn", pid,WEXITSTATUS(status)); else printf("child %d termintate abnormally n"); } exit(0); }
注意子进程退出的顺序不是一定的,如果要让父进程按照子进程创建的顺序来回收子进程,可以做出如下修改:
#includewait函数#include #include #include #include int main(){ int status,i; const int N = 10; pid_t pid[N],retpid; for(i = 0; i < N;++i){ if(fork() == 0){ exit(100+i); } } i = 0; while((retpid= waitpid(pid[i++],&status,0)) > 0){ if(WIFEXITED(status)) printf("child %d terminate normally with exit status = %dn", pid,WEXITSTATUS(status)); else printf("child %d termintate abnormally n"); } exit(0); }
wait函数时waitpid的简单版本:
#include#include pid_t wait(int *startup)
调用wait函数等价于调用waitpid(-1,&status,0)。
让进程休眠 sleep函数sleep函数会让进程挂起一段时间:
#includeunsigned int sleep(unsigned int secs);
如果挂起时间到,函数返回0,如果被中断而导致返回,将返回剩余的挂起时间。
pause函数pause函数会将进程挂起,直到进程收到一个信号
#include加载并运行新的程序int pause(void)
execve函数可以在当前进程的上下文中加载并允许一个新的程序
#includeint execve(const char* filename,const char* argv[], const char* envp[]);
其中argv与envp均指向以Null为结尾的指针数组;
在使用中,可以用environ(系统全局变量)变量传入envp[]数组中。
获取环境变量
#includechar* getenv(const char* name);
设置与取消环境变量
#includeint setenv(const char* name,const char* newvalue,int overwrite); void unsetenv(const char* name);
一般来说,环境变量已"name=value"这样键值对的方式存在。
利用进程控制接口,编写简单的shell程序#include#include #include #include #include #define MAX_COMMAND_LINE 256 #define MAX_COMMAND_COUNT 256 void eval(char* command); int parseline(char* command,char* argv[]); int builtin_command(char* argv[]); int main(){ char commandline[MAX_COMMAND_LINE]; while (1){ printf("> "); fgets(commandline,MAX_COMMAND_LINE,stdin); if(feof(stdin)){ exit(0); } eval(commandline); } exit(0); } void eval(char* command){ int argc = 0; char* argv[MAX_COMMAND_COUNT]; pid_t pid; int status; int bg = parseline(command,argv); if(argv[0] == NULL){ return ; } if(builtin_command(argv)){ return ; } if((pid = fork()) == 0){ printf("execute child n"); if(execve(argv[0],argv,__environ)<0){ printf("Can't find command %s n",argv[0]); exit(0); } } if(!bg){ if(waitpid(pid,&status,0) < 0){ printf("Fail to excute pid %d command %s n",pid,argv[0]); } if(WIFSTOPPED(status)){ printf("the stoped signal is %d n",WSTOPSIG(status)); } } else{ // waitpid(-1,&status,WNOHANG); printf("pid:%d command:%s run in background n",pid,argv[0]); } } int parseline(char* command,char* argv[]){ int argc = 0; char* delim; command[strlen(command)-1]=' '; while(*command && command[0] == ' '){ ++command; } while((delim = strchr(command,' '))){ *delim=' '; argv[argc++] = command; command = (++delim); while (*command &&command[0] == ' '){ ++command; } } argv[argc] = NULL; if(argc == 0){ return 0; } if(*argv[argc-1] == '&'){ argv[--argc] = NULL; return 1; } else{ return 0; } } int builtin_command(char* argv[]){ if(!strcmp(argv[0],"quit")){ exit(0); } else if(!strcmp(argv[0],"&")){ return 1; } return 0; }



