1、进程信息检测1.1 getid族函数:
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void);
pid_t getppid(void);
pid_t getuid(void);
pid_t geteuid(void);
pid_t getgid(void);
pid_t getegid(void);
|
作用:
getpid——返回当前进程pid;
getppid——返回当前父进程pid;
getuid——返回运行当前进程用户的UID;
geteuid——返回运行当前进程用户的有效UID(一般跟uid相同,但是在例如在setUID之后就有效UID就变成root超级用户的UID)
getgid——返回运行当前进程用户所在组的GID;
getgid——返回运行当前进程用户所在组有效GID(setGID之后和GID不同);
1.2 getlogin:返回运行当前进程的用户登录名。
#include <unistd.h>
char *getlogin(void);
|
1.3 getpwnam:输入一个有效的用户名,返回一个记录了用户各种信息的passwd结构;
#include <pwd.h>
struct passwd *getpwnam(const char *name);
|
1.4 进程计时
#include <sys/times.h>
clock_t times(struct tms *buf);
|
times:返回系统启动后流逝至今的CPU时间,并设置输入的tms结构。tms结构包括: tms_utime(用户模式下流逝的CPU时间), tms_stime(内核/系统模式下流逝的CPU时间), tms_cutime(用户模式下流逝的子进程CPU时间), tms_cstime(内核/系统模式下流逝的子进程CPU时间)。
另有rusage结构有更多的资源利用信息。它可以用getusage这个函数设置。它们都在头文件
中定义。
#include <sys/times.h>
#include <sys/resource.h>
#include <unistd.h>
int getrusage(int who, struct rusage *usage);
|
其中who为RUSAGE_SELF或者RUSAGE_CHILDREN,决定用当前进程还是子进程来设置rusage结构。
rusage结构包括timeval结构的ru_utime和ru_stime,以及记录存储IO情况的ru_minflt(引起RAM访问的次数)、ru_majflt(引起磁盘交换分区访问的次数), ru_nswap(读取的交换分区页数)等。
times调用返回的时间比getrusage要精确得多,但getrusage给出的资源利用信息要更详细。
2、进程的创建
2.1 system
#include <stdlib.h>
int system(const char *string);
|
system函数执行string所指的字符串。字符串一般为shell命令,可以包括选项和参数。例如
如果string为NULL该函数返回非零值,否则返回0;
2.2 fork
#include <unistd.h>
pid_t fork(void);
|
fork调用创建父进程的一个准确副本,包括相同的UID、EUID、GID、EGID、进程组(例如用|执行的shell命令管道就是一个进程组,用进程组PGID标识)、会话ID(会话由一个或多个进程或进程组构成,以惟一的session ID标识,创建一个shell就是创建一个shell会话)、环境变量、资源、打开的文件和共享内存段等。但是没有继承父进程的文件锁和pending未决信号。
fork执行成功后,在父进程中返回子进程的PID,在子进程中返回0。
fork调用要注意进程代码中不应有依赖父进程或子进程的代码,否则可能会引起竞态乃至系统死锁。
2.3 exec函数族
exec函数族包括6个函数:
#include <unistd.h>
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, const char *envp[]);
int execv(const char *path, const char *argv[]);
int execve(const char *path, const char *argv[], const char *envp[];
int execvp(const char *file, const char *argv[]);
|
execl的第一个参数是包括路径的可执行文件,后面是列表参数,列表的第一个为命令path,接着为参数列表,最后必须以NULL结束。
execlp的第一个参数可以使用相对路径或者绝对路径。
execle,最后包括指向一个自定义环境变量列表的指针,此列表必须以NULL结束。
execv,v表示path后面接收的是一个向量,即指向一个参数列表的指针,注意这个列表的最后一项必须为NULL。
execve,path后面接收一个参数列表向量,并可以指定一个环境变量列表向量。
execvp,第一个参数可以使用相对路径或者绝对路径,v表示后面接收一个参数列表向量。
exec被调用时会替换调用它的进程,直接返回到调用它的进程的父进程,如果出错,返回-1并设置errno。
2.4 popen
popen使用FIFO管道执行外部程序。
#include <stdio.h>
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);
|
popen通过type是r还是w确定command的输入/输出方向,r和w是相对command的管道而言的。r表示command从管道中读入,w表示command通过管道输出到它的stdout,popen返回FIFO管道的文件流指针。pclose则用于使用结束后关闭这个指针。
3. 进程控制
3.1 wait、waitpid
#include <sys/wait.h>
#include <sys/types.h>
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
|
这两个函数收集子进程的退出状态,以避免它成为僵尸进程。status为子进程的返回状态,0或-1。pid为要等待的子进程pid,可能的值有-1(等待任何PGID为PID的绝对值的子进程)、1(等待任何子进程)、0(等待任何PGID等于调用进程的子进程)、>0(pid等于PID的子进程)。option包括WNOHANG(没有子进程要退出时返回)和WUNTRACED(子进程没有要报告的状态而返回)。
3.2 中止进程的函数
进程被中止的原因包括:在main函数里面执行了return;执行了exit;执行了_exit;执行了abort;被一个信号中止。
#include <stdlib.h>
int exit(int status);
|
exit以status状态正常中止进程,如果有使用atexit登记了相关的处理程序,也可以执行。
_exit和exit不同的地方是它是在unistd.h中生命,会立刻中止调用它的进程,而且不会执行atexit登记的程序。
abort则立刻中止进程,如果系统允许还将发生core dump生成core文件,作为严重情况下使用。
使用kill函数是利用信号中止程序的一个例子。
#include <signal.h>
#include <sys/types.h>
int kill(pid_t pid, int sig);
|
pid为要杀死的进程,sig是要发送给该进程的信号,如果要杀死它,可以发送SIGKILL、SIGTERM、SIGQUIT。
3.3 信号
信号是硬件中断的软模拟,用信号量标识,为正整数,其宏定义在signal.h,均为SIG开头。
kill命令或者kill函数可以发送。与发送相对的则是捕获和处理信号。此外还有产生generate、递送deliver(信号将要被处理)、未决pending(信号已产生而未被递送的时间间隔)、忽略ignore、部署diposition(如何处理这个信号)等。多个信号可以用信号集合signal_set结构(定义在signal.h)表示。使用mask掩码可以阻塞信号以禁止它被递送。而SIGKILL和SIGSTOP是唯一两个不能被进程捕获和忽略的信号。
SIGALRM超时信号,通过alarm函数发送。
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
|
调用alarm的进程在seconds时间到后会捕获到一个SIGALRM信号。
pause函数把调用它的进程挂起,直到捕获到一个信号。如果调用pause进程不能处理递送到的信号,则发生默认部署。pause在捕获到信号后返回,而信号被递送后的处理会在pause返回前执行。pause总返回-1并设置errno。
3.4 信号的创建和处理
#include <signal.h>
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signum);
int sigdelset(segset_t *set, int signum);
int sigismember(const sigset_t *set, int signum);
|
sigemptyset:创建一个信号集合,该集合为空;
sigfillset:创建一个信号集合,该集合为满;
sigaddset:把信号signum添加到信号集合set中;
sigdelset:把信号signum从信号集合set中删除;
sigismember:测试信号signum是否在信号集合set中,如果是则返回1,否则返回0。
#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
|
sigprocmask设置或者修改信号掩码,how为对set的可选处理,包括SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK, NULL。
#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
|
sigaction为指定的信号signum设置一个信号处理器,结构sigaction描述了对该信号的部署。
#include <signal.h>
struct sigaction{
void (*sa_handler)(int);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
}
|
sa_handler规定了signum中的信号产生后要调用的处理器或者函数,输入为一个int类型参数,返回一个void,或者也可以为SIG_DFL而引起signum的默认动作,SIG_IGN忽略sinnum;
sa_mask为要阻塞的信号掩码的集合;
sa_flags掩码修正sa_handler的行为,包括SA_NOCLDSTOP(忽略子进程的SIGSTOP等信号), SA_ONESHOT(登记的自定义信号处理器只执行一次,然后恢复信号的默认动作), SA_RESTART(让可重启的系统调用起作用), SA_NOMASK, SA_NODEFER。
sa_restorer:已经废弃不用。
#include <signal.h>
int sigpending(sigset_t *set);
|
sigpending检查是否有未决信号并设置到set中,如果挂起信号是为了执行某个操作,操作完成后可以用sigpending检查未决信号并处理之。否则简单接触阻塞就可以。
4. 进程的调度
#include <sched.h>
int sched_setscheduler(pid_t pid, int policy, const struct sched_param *p);
int sched_getscheduler(pid_t pid);
int sched_get_priority_max(int policy);
int sched_get_priority_min(int policy);
int getpriority(int which, int who);
int setpriority(int which, int who, int prio);
int nice(int inc);
|
sched_setscheduler和sched_getscheduler分别设置和取得与某个特定进程相关的策略和参数。策略policy包括SCHED_OTHER、SCHED_FIFO、SCHED_RR。后两者是用于特别看重时间的策略,会抢先于使用默认策略SHED_OTHER的进行执行;
sched_get_priority_max和sched_get_priority_min返回对于策略policy来说最大或最小的优先级。注意优先级的值越小,其级别越高;
setpriority设置进程(which=PRIO_PROCESS)、进程组(which=PRIO_PGRP)、用户(which=PRIO_USER)的动态优先级;
getpriority则返回匹配进程的最高优先级(最小值);
nice通过为当前的进程优先级增加一个inc而降低其优先级。
阅读(1930) | 评论(0) | 转发(0) |