五、linux应用编程之三:进程基本操作
linux是一个多任务多用户的系统,可以同时运行多个程序。进程是正在被运行的程序,一个进程至少由一个或者多个线程组成。程序转变为进程的过程是:shell命令运行程序->系统寻找程序文件->fork()函数创建一个新进程->在新进程中用exec族函数装在main()函数。划重点,fork()建立新进程,exec装在程序。所有新进程在被内核创建时都会分配一个唯一的进程ID(PID),如果这个新进程有父进程的话,还会有父进程ID(PPID)。因为linux系统是多任务系统,而CPU的个数却是限定的,所以某个进程不能一直都在运行,要把CPU处理时间让给其他进程,因而进程有6种状态:不可中断的睡眠状态(D),运行或者准备就绪状态(R),可中断的睡眠状态(S),暂停状态(T),即将退出状态(X),僵尸进程状态(Z)。进程基本操作包括:创建进程,终止进程,用exec族函数加载不同的函数。
创建进程
1) 函数原型 : pid_t fork(void);
2) 函数输入 : 无;
3) 返 回 值 : pid_t,成功返回子进程的pid,失败返回-1;
4) 示 例 : pid_t pid = fork();
5) 说 明 : 创建子进程成功后,父进程和子进程的代码是一样的,而且父进程和子进程都是运行态。唯一不同的是,在子进程中fork()返回的值是0,而父进程中fork()的返回值是子进程的pid,所以在代码中可以用if判断pid的值是否等于0,判断成立的代码段就是子进程要运行的代码段,判断不成立的代码段就是父进程要运行的代码段。
终止进程
1) 函数原型 : 正常终止void exit(int status);/异常终止abort()函数
2) 函数输入 : status,终止状态,正常终止可以写0;
3) 返 回 值 : 无
4) 示 例 : exit(0);
5) 说 明 1 : return 0;实际上也是调用了exit(0);
6) 说 明 2 : 如果子进程终止的时候,父进程没有为其运行wait()函数,则子进程将变成僵尸进程,一直占用系统资源无法终止。所以父进程中一般要加上if(wait(&statue) != pid)来判断子进程是否可以终止,分析statue的状态可以知道是正常终止还是异常终止。wait()函数原型为:pid_t wait(int *status);,意思是等待接收子进程的终止状态,程序会卡在这个函数,知道子进程终止或出错。
exec族函数
调用exec族函数可以调用可执行文件,在子线程中可以调用exec族函数加载另一个程序运行。exec族函数一共有6个函数,作用是一样的,只是使用语法和规则有细微差别。
1) int execl(const char *path, const char *arg, ...);
2) int execlp(const char *file, const char *arg, ...);
3) int execle(const char *path, const char *arg,..., char * const envp[]);
4) int execv(const char *path, char *const argv[]);
5) int execvp(const char *file, char *const argv[]);
6) int execve(const char *path, char *const argv[],char *const envp[]);
因为暂时还没使用过传递环境变量,所以e结尾的两个函数暂时先不用。
观察发现所有函数都是exec开头的,只是后面一位或者两位字母有区别。实际上,后缀有l表示加载程序时以列表(变元)形式输入参数,参数就一次写在括号内,以逗号间隔。而后缀有v表示以指针的形式传递新程序的参数,即所有要输入的参数事先写到一个字符串数组里,然后调用函数的时候再引用字符串数组的指针。显然后缀l和后缀v是互斥的,不可能既是l又是v。后缀有p表示调用函数的时候*file参数可以只写文件名而不写路径名,此时系统会从环境变量指定的路径中寻找该文件,如果既写了文件名,又写了路径名,则和没有后缀p一样。下图列举了6个函数的使用范例:
应该注意到的是,运行新程序时argv的第一个参数是文件名,argv[1]之后的值才是真正的参数。
综合实例:
在一个程序内创建一个子进程,然后在子进程中调用之前写好的file文件。
#include#include #include int main(){ int statue; pid_t pid; pid = fork(); //creat child process if(pid == 0){ //child process printf("here is child process,my pid = %d\n",getpid()); execl("/mnt/file","file",NULL); exit(-1); } else if(pid > 0){ //parent process printf("here is parent process, my pid = %d\n", getpid()); if(pid != wait(&statue)){ printf("child process exit error\n"); exit(-1); } printf("child process exit succeed\n"); exit(0); } else printf("creat process fault\n"); return -1;}
运行结果: