进程正常终止5种方式:
1.main函数返回
2.调用exit库函数
3.调用_exit或_Exit系统调用
4.最后一个线程从其启动例程返回
5.最后一个线程调用pthread_exit库函数
进程异常终止3种方式:
1.调用abort库函数,产生abort信号。
2.接到一个信号并终止
3.最后一个线程对取消请求做出响应
init进程:pid=1的进程,如果父进程先于子进程终止,子进程就被init进程收养。
孤儿进程:父进程先于子进程退出,子进程被init进程收养,这个子进程就是孤儿进程。
僵死进程:已经终止,但是父进程没有进行善后处理的进程。
##################################################
进程相关的系统调用
##################################################
#include<unistd.h>
void_exit(int status);
#include<stdlib.h>
void_Exit(int status);
#include<sys/time.h>
#include<sys/resource.h>
intgetrlimit(int resource, struct rlimit *rlim);
传入资源名称返回资源结构信息。
intsetrlimit(int resource, const struct rlimit *rlim);
设置资源结构。
structrlimit {
rlim_trlim_cur; //软限制
rlim_trlim_max; //硬限制
};
resource:
RLIMIT_AS
RLIMIT_CORE
RLIMIT_CPU
RLIMIT_DATA
RLIMIT_FSIZE
RLIMIT_LOCKS
RLIMIT_MEMLOCK
RLIMIT_MSGQUEUE
RLIMIT_NICE
RLIMIT_NOFILE
RLIMIT_NPROC
RLIMIT_RSS
RLIMIT_RTPRIO
RLIMIT_RTTIME
RLIMIT_SIGPENDING
RLIMIT_STACK
#include<unistd.h>
#include<sys/types.h>
pid_tgetpid(void);
返回调用进程的进程ID
pid_tgetppid(void);
返回调用进程的父进程ID
uid_tgetuid(void);
返回调用进程的实际用户ID
uid_tgeteuid(void);
返回调用进程的有效用户ID
intsetuid(uid_t uid);
设置调用进程的实际用户ID和有效用户ID
只有超级用户可以改变实际用户ID
普通用户只能改变有效用户ID
intseteuid(uid_t euid);
更改有效用户ID
intsetreuid(uid_t ruid, uid_t euid);
交换实际用户ID和有效用户ID的值,如果有一个参数为-1,表示相应的值不变。
gid_tgetgid(void)
返回调用进程的实际组ID
gid_tgetegid(void);
返回调用进程的有效组ID
intsetgid(gid_t gid);
设置调用进程的实际组ID和有效组ID
intsetegid(gid_t egid);
更改有效组ID
intsetregid(gid_t rgid, gid_t egid);
交换实际组ID和有效组ID的值,如果有一个参数为-1,表示相应的值不变。
#include<unistd.h>
pid_t
getpgid(pid_t pid);
成功返回进程组ID,失败返回-1.pid=0,返回调用进程的进程组ID
pid_tgetpgrp(void);
返回调用进程的进程组ID。
intsetpgid(pid_t pid, pid_t pgid);
加入现有的组,或创建一个新进程组。
一个进程只能为自己或子进程设置组ID,子进程调用exec之后也不能设置组ID。
将pid进程的进程组ID设置为pgid;如果pid=0,则pid=调用者的进程ID,如果pgid=0,则pgid=pid。
成功返回0,失败返回-1.
#include<unistd.h>
pid_tsetsid(void);
成功返回进程组ID,失败返回-1.
创建一个新的会话,如果调用进程是组长进程则失败,否则调用进程变成新会话首进程和新进程组组长进程,且该进程没有控制终端。
pid_tgetsid(pid_t pid);
返回会话首进程的进程组ID,失败返回-1.
如果pid=0返回调用进程的会话首进程组ID。
#include<unistd.h>
pid_tfork(void); //创建新进程。
调用一次,返回两次,在父进程返回子进程的ID,在子进程返回0.
Pid= fork()
pid>0只是父进程执行
pid==0只是子进程执行
后面的不在pid>0和pid==0范围之内的程序,父子进程都要执行,除非某个进程终止了。
子进程继承父进程的下列属性:
1.父进程的所有的打开的文件描述符
2.实际用户ID和组ID、有效用户ID和组ID
3.附加组ID、进程组ID、会话ID
4.设置用户ID标识和设置组ID标志。
5.控制终端、根目录、当前工作目录
6.文件模式创建屏蔽字、信号屏蔽和安排
7.环境、存储映像、资源限制、连接的共享存储段
8.针对任一打开文件描述符的在执行时关闭标志。
子进程和父进程的区别:
1.进程ID不同
2.父进程ID不同
3.父进程设置的文件锁不会被继承
4.子进程的未处理的闹钟被清理
5.子进程的未处理信号集设置为空集
6.子进程的tms_utime,tms_stime,tms_cutime,tms_ustime设置为0.
#include<sys/types.h>
#include<sys/wait.h>
pid_twait(int *status); //= waitpid(-1, &status, 0);
参数用来保存进程退出时的状态,不关心可以为NULL。
返回子进程的ID,出错返回-1.
进程一旦调用wait,就立即阻塞自己,如果一个子进程是僵死进程,wait立即返回,并取得该子进程的退出状态;否则等到当前进程的某个子进程终止才返回。
pid_twaitpid(pid_t pid, int *status, int options);
status参数用来保存进程退出时的状态,不关心可以为NULL。
成功返回已经终止子进程的ID;如果WNOHANG指定,pid指定的进程状态都没有变化,返回0;出错返回-1
pid:
指定要等待的进程ID
-1:等待任何子进程,和wait一样
<-1:等待组ID=|pid|的子进程
0:
组ID=调用进程组ID的任何子进程
>0:等待ID=pid的指定子进程
options:可以是0.
WNOHANG:指定的子进程不能立即可用,不阻塞,函数返回0.
WUNTRACED:指定的子进程处于暂停状态,状态没报告,返回其状态。
WCONTINUED:指定的子进程在暂停后继续,状态没报告,返回其状态。
可用宏判断一些status状态:
WIFEXITED(status),如果子进程正常退出,返回真。
WEXITSTATUS(status),返回子进程退出状态,取低8位。
WIFSIGNALED(status),如果是异常终止子进程,返回真。
WTERMSIG(status):获取异常退出的信号。
WIFSTOPPED(status):若为当前暂停子进程的返回状态,返回真。
WSTOPSIG(status):获取暂停进程的信号。
WCOREDUMP(status):产生core文件,返回真。
WIFCONTINUED(status):若在作业暂停后已经继续的子进程返回了状态,返回真。只能用于waitpid。
intwaitid(idtype_t idtype, id_t id, siginfo_t *infop, intoptions);
成功返回0,失败返回-1.
idtype:
P_PID:等待一个特定的进程,id包含要等待子进程的进程ID
P_PGID:等待一个特定进程组中的任一子进程,id包含要等待子进程的进程组ID
P_ALL:等待任一子进程,ID忽略。
Options:
WCONTINUED:等待一个暂停后又继续的进程,状态未报告。
WEXITED:等待已退出的进程
WNOHNAG:如果没有可用的子进程退出状态,立即返回
WNOWAIT:不破坏子进程退出状态
WSTOPPED:等待一个暂停的进程,状态未报告。
intexecve(const char *path, char *const argv[], char *constenvp[]);//参数数组,只有这个函数是系统调用。
exec的一个系统调用,其它留个库函数都是调用这个函数。
#include<sys/times.h>
clock_ttimes(struct tms *buffer);
返回的是墙上时钟时间,失败返回-1.两次调用获取的时间差才是真正滴答数。
返回的墙上时钟时间(滴答数)需要用_SC_CLK_TCK宏转换成秒,也就是用滴答数/sysconf(_SC_CLK_TCK)=实际时间(rtime)
structtms {
clock_ttms_utime; //用户cpu时间
clock_ttms_stime; //系统cpu时间
clock_ttms_cutime; //终止子进程的用户cpu时间
clock_ttms_cstime; //终止子进程的系统cpu时间
}
##################################################
进程相关库函数
##################################################
#include<stdlib.h>
voidexit(int status);
status:
0:= EXIT_SUCCESS , exit with normal
1:= EXIT_FAILURE , exit with failure
#include<stdlib.h>
intatexit(void (*function)(void));
调用该函数注册终止处理程序,这些程序由exit(在mai函数中exit和return一样)自动调用。成功返回0,失败返回非0.
参数是终止处理程序的地址,该函数没有参数和返回值。
#include <stdlib.h>
存储器分配函数:
成功返回非空指针,失败返回NULL。
void*malloc(size_t size);
分配指定字节的存储区,用于整型、浮点型、字符和字符串。
void*calloc(size_t nmemb, size_t size);
分配指定数量和指定长度的对象,用于结构、结构数组、数组等
void*relloc(void *ptr, size_t newsize);
更改以前分配区的长度。
存储器释放函数:
voidfree(void *ptr);
#include<stdlib.h>
char*getenv(const char *name);
根据环境变量名字name返回它的值,出错返回NULL。
intsetenv(const char *name, const char *value, int overwrite);
将环境变量name设置为value,overwrite=0表示不覆盖,否则覆盖。
intunsetenv(const char *name);
删除环境变量name。
linux常用的环境变量:
HOME
LANG
LOGNAME
PATH
PWD
SHELL
...
#include<setjmp.h>
处理子函数中发生的错误和中断:
intsetjmp(jmp_buf env);
在希望返回的地方调用该函数,直接调用返回0.从longjmp调用返回非0值val。
voidlongjmp(jmp_buf env,int val);
发生错误等可以调用该函数,env是setjmp使用的env,val是从setjmp返回的非0值。
exec的六个函数:执行一个新程序。
出错返回-1,成功不返回。
#include<unistd.h>
externcahr **environ;
用程序路径:
intexecl(const char *path, const char *arg0,…, (char*)0);//单个参数传递,最后要用0结束
intexecv(const char *path, char *const argv[]);//参数数组
用程序路径,带环境变量
intexecle(const char *path, const char *arg0, …, (char *)0,char *const envp[]);//单个参数,要用0结束
用程序名称:
intexeclp(const char *file, const char *arg0,…, (char *)0);//单个参数,要用0结束
intexecvp(const char *file, char *const argv[]);//参数数组
用程序名称,带环境变量
intexecvpe(const char *file, char *const argv[], char *constenvp[]); //参数数组
用exec函数执行新程序的进程保持了原进程的下列特性:
1.进程ID和父进程ID、实际用户ID和实际组ID、附加组Id和进程组ID、会话ID
2.控制终端
3.闹钟尚余留的时间
4.当前工作目录、根目录
5.文件模式创建屏蔽字、文件锁
6.进程信号屏蔽、未处理信号
7.资源限制
8.tms_utime\tms_stime\tms_cutime\tms_cstime的值。
#include <stdlib.h>
intsystem(const char *command);
执行一个shell命令。
该函数由fork、exec、waitpid三个函数组成:
失败返回-1;exec不能执行不算失败;成功返回退出状态,可以根据waitpid的status宏检验和获取退出状态。
#include<unistd.h>
char*getlogin(void);
用来查找运行当前进程的用户名
成功返回指向登录名的指针,失败返回NULL。
#include<termios.h>
pid_ttcgetsid(int fd);
返回会话首进程的进程组ID,失败返回-1.
#include<unistd.h>
pid_ttcgetpgrp(int fd);
返回前台进程组的进程组ID,出错返回-1.
inttcsetpgrp(int fd, pid_t pgrp);
设置前台进程组ID,成功返回0,失败返回-1.
未完待续......