##进程控制
#进程标识符
#include <unistd.h>
1. pid_t getpid(void); 获取当前进程的ID
2. pid_t getppid(void); 获取父进程的ID
3. uid_t getuid(void); 获取进程实际用户ID
4. uid_t geteuid(void); 获取进程的有效用户ID
5. gid_t getgid(void); 获取进程的实际组ID
6. gid_t getegid(void); 获取进程的有效组ID
7. pid_t fork(void); 创建一个新进程
创建进程后,两个进程谁先执行是不确定的
IO是共享的,文件锁不会被继承,其他资源为拷贝
8. vfork 创建一个新进程
此函数不拷贝资源副本,且此函数保证子进程先执行
#进程退出
exit(0); 正常退出,清理运行环境
_Exit(); ISO C _exit(); POSIX 函数 不清理运行环境
0 为正常退出 其他说明为错误退出
abort(); 产生SIGABRT信号,系统默认处理信号来停止
#父子进程
wait 在 SIGCHLD 信号中处理避免阻塞问题
#include <sys/wait.h>
父进程比子进程先停止,子进程的父进程将改为init PID:1
子进程比父进程先停止,子进程僵死Z,需要父进程处理:
1. pid_t wait (int *statloc);
等待任何一个进程退出,进程阻塞
2. pid_t waitpid(pid_t pid,int *statloc,int option);
等待指定进程退出
pid = -1 与 wait 一样
pid=0 同组子进程
pid>0||pid<-1 指定pid的子进程
option WCONTINUED 作业控制 WONHANG 不阻塞返回:0 WUNTRACRD 作业控制未报告返回
处理 wait函数返回
判断statloc 值
WIFEXITED(statloc); 子进程正常终止
WIFSIGNALED(statloc); 子进程异常中止,以下为辅助宏:
WTERMSIG(statloc); 获取终止子进程的信号编号
WCOREDUMP(statloc); 判断是否产生core文件(不是所有平台都有)
WIFSTOPPED(statloc); 子进程处于暂停状态
WIFCONTINUED(statloc);作业控制继续
3. int waitid(idtype_t idtype,id_t id.siginfo *infop,int options);
类似waitpid 功能
idtype_t 可选值 P_PID : 指定子进程ID P_PGID :指定组进程子ID P_ALL :何以子进程
*infop 返回子进程的状态信息
options 可选值 WCONTINUED WEXITED WONHANG WNOWAIT WSTOPPED
4. pid_t wait3(int & statloc,int options,struct rusage &rusage);
5. pid_t wait4(pid_t pid,int *statloc,int options,struct rusage *rusage);
#竞争条件
由于两个进程谁先执行,所以进程间要相互依赖时候,需要相互等待
#exec函数,返回为子指定程序的exit值
#include <unistd.h>
1. int execl(const char* pathname,const char * arg,.../*(char *)0*/);
2. int execv(const char* pathname,char * const argv[]);
3. int execle(const char * pathname,const char *arg,...
/*(char *)0,char * const envp[] */);
4. int execve(const char *pathname,char * const argv[],char * const envp[]);
5. int execlp(const char * filename,const char *arg,.../*(char *)0 */);
6. int execvp(const char * filename,char * const argv[]);
#更改用户ID和组ID 无权限修改后值不变
#include <unistd.h>
1. int setuid(uid_t uid);
2. int setgid(gid_t gid);
3. int seteuid(uid_t uid);
4. int seteuid(uid_t uid);
备注:
root 或chmod u+s 修改实际用户
root 或chmod g+s 修改实际用户组
#解析器文件:
#include <stdlib.h>
int system(const char *cmdstring);
有调用此函数的程序禁止给root权限
#用户标识:
#include <unistd.h>
char * getlogin(void); 出错返回NULL
#进程时间: 子进程清0
#include <sys/times.h>
clock_t times(struct tms *buf); 填写当前CPU时间
struct tms{
clock_t tms_utime;
clock_t tms_stime;
clock_t tms_cutime;
clock_t tms_cstime;
};
clock_t 为滴答数,转换秒处于系统每秒滴答数:sysconf(_SC_CLK_TCK);
##进程关系
#进程组
与统一作业关联,可以接收来自同一终端的各种信号
进程组ID默认等于其进程ID
#include <unistd.h>
pid_t getpgrp(void); 取得当前进程的进程组ID
pid_t getpgid(pid_t pid); 获取指定进程的进程组ID 0等于getpgrp
int setpgid(pid_t pid,pid_t pgid); 设置进程的进程组ID
#会话
多个进程组 组成一个会话
#include <unistd.h>
pid_t setsid(void); 设置一个新会话
pid_t getsid(pid_t pid); 获得一个会话ID
##信号
linux: <bits/signal.h>
maxos&&freebsd: <sys/signal.h>
solaris: <sys/iso/signal_iso.h>
#include <signal.h>
子进程将继承父进程的信号处理方法
#UNIX系统信号(具体:**)
SIGKILL 终止信号
SIGCHLD 子进程终止向父进程发送的信号
SIGCLD 系统V的子进程终止信号(不要用)
#signal 函数
1. void (*signal(int signo,void(*func)(int)))(int);
2. typeof void sigfun(int);
sigfun * signal(int,sigfun *);
#系统信号处理函数(宏)
SIG_ERR
SIG_DFL
SIG_IGN
#可重入函数
因为无法预知程序执行情况,所以在实现信号处理函数时候,不要使用不可重入函数
#可信信号术语
重复多个相同信号(未处理的时候)只保留传送一个,信号传送没有顺序
#发送信号
#include <signal.h>
int kill (pid_t pid,int signo); 向指定进程发送信号,需要权限
pid >0 发送信号到指定进程
pid==0 发送给自己
pid ==-1 给所有有权限发送信号的进程发送信号
pid <0 pid的绝对值发送信号
int raise(int signo); 给自己发送信号
#include <unistd.h>
unsigned int alarm(unsigned int seconds); 设置计时器
但上一个计时器没完成,在调用者复位定时器重新计时
int pause(void); 产生一个暂停信号
#信号集 作用,告诉内核不可以发生该信号集的信号
#include <signal.h>
int sigemptyset(sigset_t *set); 清除所有信号
int sigfillset(sigset_t *set); 重置信号
int sigaddset(sigset_t *set,int signo); 添加信号
int sigdelset(sigset_t *set,int signo); 删除信号
int sigismember(const sigset_t *set,int signo); 检查是否有指定信号
int sigprocmask(int how,const sigset_t *restric set,sigset_t *restirc oset);
把建立好的信号提交给内核或从内核取出当前的屏蔽信号
oset 非空,当前进程的屏蔽信号通过oset返回
set 非空,根据how的指示来修改当前的屏蔽信号 (对于SIGKILL SIGSTOP无效)
how 取值: SIG_BLOCK 新加新的屏蔽信号 (并集)
SIG_UNBLOCK 删除指定的屏蔽信号 (交集)
SIG_SETMASK 用当前屏蔽信号代替原来的屏蔽信号
int sigpending(sigset_t *set);
当信号被屏蔽之后,只是不传送给程序,信号在内核阻塞
调用此程序可以获取被阻塞的这些没有处理的信号
当屏蔽取出之后,信号将立即会被传送,相当于调用sigprocmask解除屏蔽后执行
#新信号处理函数
#include <signal.h>
int sigaction(int signo,const struct sigaction *restrict act,
struct sigaction * restrict oact);
信号处理函数设置,可以代替signal函数
signo 信号编号
act 非空,修改信号处理动作
oact 非空.返回原来的处理动作
struct sigaction{
void (*sa_handler)(int);/*信号处理函数*/
sigset_t sa_mask;
/*发生信号处理时,将该信号添加到屏蔽信号集,必须初始化0
返回时候恢复原信号集(为了保证未返回时候正常,需要使用siglongjmp函数),
可以让某些信号在此信号之后触发*/
int sa_flags;
/*对信号处理的选项,对信号的发生的调整,
可以多选值,用 | 连接参考page 262,表10-5*/
void (*sa_sigaction)(int,siginfo_t *,void *);
/*但sa_flags 为SA_SIGINFO时候用该函数处理信号
用此函数处理信号可以得到产生此信号发生时的相关信息
关于siginfo_t 的结构可以参考page 263*/
}
#sigsetjmp与siglogjmp 函数
但信号进入信号处理函数前,当前信号会被添加到信号屏蔽集里
但时候logjmp跳出该信号处理函数时候,有些系统不会将当前信号从信号屏蔽里移除
所以为了兼容,在信号处理函数里面,使用siglogjmp跳转程序
siglogjmp 还会恢复sigsetjmp保留的关键子
#include <setjmp.h>
int sigsetjmp(sigjmp_buf env,int savemask); 设置一个跳转点
void siglongjmp(sigjmp_buf env,int val); 跳转到指定跳转点
#sigsuspend函数
#include <signal.h>
int sigsuspend(const sigset_t *sigmask);
sigmask 为提供给内核的屏蔽信号集
该函数的作用是在接到一个信号之前将程序挂起,
直到接到一个信号处理函数处理完后返回
作用是防止信号冲突程序被挂起