UNIX环境高级编程---- 进程

来源:互联网 发布:des算法与rsa算法 编辑:程序博客网 时间:2024/04/28 22:38

进程是操作系统结构的基础;是一个正在执行的程序;计算机中正在运行的程序实例;可以分配给处理器并由处理器执行的一个实体;由单一顺序的执行显示,一个当前状态和一组相关的系统资源所描述的活动单元。

进程终止的8种方式

1)  从main返回

2)  调用exit

3)  调用_exit或_Exite

4)  最后一个线程从其启动例程返回

5)  最后一个线程调用pthread_exit

异常终止方式

6)  调用abort

7)  街道一个信号并终止

8)  最后一个线程对取消请求作出响应

_exit和_Exit函数立即进入内核,而exit则先执行一些清理处理(关闭标准I/O流等)然后进入内核,即为所有打开刘调用fclose函数。

 

atexit函数:注册用exit自动调用的函数,exit调用顺序与注册顺序相反。

#include <stdlib.h>

Int atexit(void (*func) (void));成功返回0, 出错返回-1

实例:

#include <stdio.h>#include <errno.h>#include <string.h>#include <stdlib.h>void func1(void);void func2(void);int main(int argc, char **argv){if(atexit(func1) < 0){printf("atexit error:%s\n", strerror(errno));exit(1);}if(atexit(func2) < 0){printf("atexit error:%s\n", strerror(errno));exit(1);}printf("main function is called\n");exit(0);}void func1(void){printf("Function 1 is called\n");}void func2(void){printf("function 2 is called\n");}

运行结果:

进程标识符:每个进程都有一个非负整型表示的唯一进程ID,虽然进程ID是唯一的,但进程ID可以重用,当一个进程终止后其进程ID就可以再次使用,大多数UNIX系统实现延迟重用算法,使得赋予新进程的ID不同于最近终止进程所使用的ID。

ID为0的进程通常是调度进程,是内核的一部分,ID为1的是init进程,在自举过程结束时由内核调用,init进程决不会终止,它是一个普通进程的用户进程,但是它以超级用户特权运行。

获取进程ID函数;

#include <unistd.h>

pid_t getpid(void);返回值:调用进程的进程ID

pid_t getppid(void);返回值:调用进程的父进程ID

 

创建进程函数:

#include <unistd.h>

pid_t fork(void);返回值:子进程中返回0,父进程中返回子进程ID,出错返回-1;

fork函数创建的新进程称为子进程,fork函数被调用一次,但返回两次,两次返回的唯一区别是子进程的返回值为0,而父进程的返回值则是子进程的进程ID,子进程和父进程继续执行fork调用之后的指令,子进程是父进程的副本,子进程获得父进程的数据空间,堆和栈的副本,也就是说子父进程不共享存储空间,子进程对变量所做的改变不影响父进程。

在一个进程终止时,内核会逐个检查所有活动进程,以判断它是否是正要终止进程的子进程,如果是,则将该进程的父进程ID改为1,以保证每个进程都有一个父进程,这就是init进程领养。

内核为每个终止子进程保存了一定量的信息,所有当终止进程的父进程调用wait或waitpid时可以得到这些信息,包括进程ID,进程的终止状态,记忆该进程是有的cpu时间总量,内核可以释放终止进程所使用的所有存储区,关闭其所有打开文件。

一个已经终止,但是其父进程尚未对其进行善后处理(wait,waitpid获取终止子进程有关信息,释放它仍占用资源)的进程被称为僵死进程。

 

wait ,waitpid 函数:

#include <sys.wait.h>

pit_t wait(int *statloc);

pit_t waitpid(pid_t pid, int *statloc, int options)两个函数返回值:若成功返回终止进程ID, 0, 若出错返回-1:

statloc是一个整型指针,如果statloc不是一个空指针,则终止进程的终止状态就存放在它所指向的单元内。如果不关心终止状态,则可将该参指定为空指针。

waitpid 函数的pid参数解释如下:

pid== -1 等待任何一个子进程,就这一方面而言waitpid与wait等效

pid>0 等待期进程ID与pid相等的子进程

pid==0 等待其组ID等于调用进程组ID的任一子进程

pid<0 等待其组ID等于pid绝对值的任一子进程

waitpid 函数options参数可以使我们进一步控制waitpid操作,此参数通常是0;

两个函数区别:

1)在一个子进程终止前,wait使其调用者阻塞,而waitpid有一个选项,可使调用者不阻塞。

2)waitpid可以指定等待特定的子进程终止。

fork两次避免僵死进程:

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/wait.h>#include <errno.h>int main(int argc, char **argv){pid_t pid;if((pid = fork()) < 0){printf("fork error:%s\n", strerror(errno));exit(1);}else if(pid == 0){if((pid = fork()) < 0){printf("fork error:%s\n", strerror(errno));exit(1);}else if(pid > 0){exit(0);}sleep(2);printf("second child, parent pid=%d\n", getppid());exit(0);}if(waitpid(pid, NULL, 0) != pid){printf("waitpid error:%s\n", strerror(errno));exit(1);}exit(0);}

运行结果:

exec函数:在用fork函数创建子进程后,子进程往往要调用一种exec函数以指向另一个程序,当进程调用一种exec函数时,该进程执行的程序完全替换为新程序,而新程序则从其main函数开始执行。

 

说是exec系统调用,实际上在Linux中,并不存在一个exec()的函数形式,exec指的是一组函数,一共有6个,分别是:

#include <unistd.h>

extern char **environ;

int execl(const char *path, const char *arg, ...);

int execlp(const char *file, const char *arg, ...);

int execle(const char *path, const char *arg, ..., char * const envp[]);

int execv(const char *path, char *const argv[]);

int execvp(const char *file, char *const argv[]);

int execve(const char *path, char *const argv[], char *const envp[]);

其中只有execve是真正意义上的系统调用,其它都是在此基础上经过包装的库函数。

Exec函数实例:

#include<unistd.h>main(){execlp(“ls”,”ls”,”-al”,”/etc/passwd”,(char *)0);}


原创粉丝点击