1,关于真实和有效用户,用户组的说明:
仅拿用户来说明,组原理类似。
真实用户是你登陆的时候所使用的用户名的数字化表示。它在你的登陆期間不会
被改变,是你最本质的品质。
有效用户是指在执行一个程序时变成另外的权限的用户。举个例子,古代的一个
刺史,它平时真实身分就是一个刺史,可当他要行使超越自己权限的法办时,比如
惩罚一个比他更高的官员,这时,如果他有一个尚方宝剑(具有皇帝的权力),这
时他的 有效身份就是皇帝。但平时,这个有效身份和他的真实身份是一样的。

真实用户ID: getuid(void);
有效用户ID: geteuid(void);
真实用户组ID: getgid(void);
有效用户组ID: getegid(void);
2,得到用户和用户组的信息
getlogin函数可以返回执行程序的用户的登陆名。然后这个登陆名可以作为参数
传递给getpwname函数,从而返回/etc/passwd文件中与该登录名相应的一行完整信
息。另种方法是,将进程的UID传递给getpwuid函数,同样返回/etc/passwd文件中
合适的条目。
#include <unistd.h>
char *getlogin(void);

#include <pwd.h>
struct passwd *getpwnam(const char *name);
3,linux 进程的三个独立的时间值
Wall clock time(墙上时钟时间)是流逝的时间
User CPU time(用户CPU时间)是进程花在执行用户模式(非内核模式)代码上的
时间总量
System CPU time(系统CPU时间)是花在执行内核代码上的时间总是。
通过times或getrusage可以获得这些信息。
#include <sys/times.h>
clock_t times(struct tms *buf);
返回墙上时钟时间,buf保存了当前进程的时间。
在<sys/times.h>定义的tms结构
struct tms {
clock_t tms_utime; // User CPU time
clock_t tms_stime; //System CPU time
clock_t tms_cutime; //User CPU time of chilren
clock_t tms_cstime; //System CPU time of chilren.
这值值clock_t都是时钟滴答数,要转换成秒还要通过sysconf函数转换。
_SC_CLK_TCK是定义每秒钟有多少滴答的宏。

4,资源利用信息
利用函数getrusage
#include <sys/times.h>
#include <sys/resource.h>
#include <unistd.h>
int getrusage(int who, struct rusage *usage);
这里重点在于usage上,而who参数只能取值RUSAGE_SELF或RUSAGE_CHILDREN,表示
是返回调用进程的资源利用信息还是子进程的资源利用信息。这里对包含
在<sys/resource.h>的rusage结构进行说明:
struct rusage {
struct timeval ru_utime; // user time used
struct timeval ru_sutime; // system time used
long ru_maxrss; // maximum resident set size
long ru_maxixrss; // shared memory size
long ru_maxidrss; // unshared data dize
long ru_maxisrss; // unshared stack size
long ru_minflt; // page reclaims
long ru_majflt; // page faults
long ru_nswap; // swaps
long ru_inblock; // block input operations
long ru_outblock; // block output operations
long ru_msgsnd; // message sent
long ru_msgrcv; //message received
long ru_nsignals; // siganls received
long ru_nvcsw; // voluntary contex switches
long ru_nivcsw; //involuntary contex switches
}

说明
但linux只支持资源:
ru_utime--用户模式(非内核)代码时间
ru_stime--内核代码的时间
ru_minflt--次要失效数(访问内存而没有引起磁盘访问)
ru_majflt--主要失效数(内存访问引起磁盘访问)

5,会话和进程的概念
有的情况中进程间不能简单的用父子来概括,如果对于管道,涉及到几个进程,
这时,这些相关的进程就成为进程组,可以被统一控制(如杀死)。一个进程
组(process group)是相关进程的一个集合,这些相关进程能和是在一个管道的命
令序列。都进程组中的所有的进程都有相同的进程组号,即PGID.使用进程组的目
的是为了方便作業控制。例如,假定你运行了命令行管道 ls -l /usr/include |
sort | wc -l.如果要在其还在运行时杀死它(按Ctrl+C),则shell需能终止所有
的进程。它通过杀死进程组而不是每个进程来做到这一点。
会话(session)是由一个或多个进程组构成,会话领导(session leader)进程是创
建会话的进程,每个会话都有惟一标识号,称为会话ID(session ID),它只是会话
领导的进程PID。会话对进程组起的作用和进程组对单个进程起的作用一样。方便
控制。

6,fork
#include <unistd.h>
pid_t fork(void);
成功向父进程返回子进程的PID,向子进程返回0.
子进程和父进程有一样的真实和有效的UID,GID,进程组和会话ID,环境,资源限
制,打开的文件以及共享内存段。但子进程不继承父进程的超时设置(alarm调
用),父进程创建的文件锁,未决信号。
7,exec函数族
以前作过笔记,再复习一次。
#include <unistd.h>
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const *path, const char *arg,char *cont envp[]);
int execv(const char *path, char *const argv[]);
int execve(const char *path, const argv[], char *const envp[]);
int execvp(const char *file, char *const argv[]);

相关的,操控进程运行的环境的函数:
#include <stdlib.h>
int utenv(const char *string);
char *getenv(const char *name);
说明:getenv查找名为name的环境变量并返回指向其值的指针,如果没有找到则
返回NULL。putenv添加或改变string中指定的"name = value" 对。如果它执行成
功,则返回0,如果执行失败,则返回-1.

8,popen函数
它和system函数行为类似,但它是一种无需使用fork和exec就能在执行外部的程
序的簡易方法。但和system不同,popen使用管道来工作。原型
#include <stdio.h>
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);
说明:popen调用管道,并创建通过标准输入,或者从command指定的程序或脚本
的标准输出来的管道,但不是两者都有。第二个参数type在读取管道的stdout时为
r,在写入stdin时为w.它和I/O的用法有点违反直觉。请写都是相对于command而言
的,所以command的输出是从stdout读入的。要向command输入,则需向它的stdin
写入。
9,等待进程--wait 函数族
只有两个函数
#include <sys/wait.h>
#include <sys/types.h>
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
说明,status保存了进程的退出状态,而waitpid中pid 可能取值:
-1 等待任何PGID==PID绝对值的子进程
1 等待任何子进程
0  等待任何PGID==调用进程的子进程
>0 等待PID==pid的子进程
对于option决定调用的行为,可以是WNOHANG导致在没有子进程退出时立即返回。
也可以是WUNTRACED,在没有报告状态的进程而返回。

10, kill函数杀死进程。
#include <signal.h>
#include <sys/types.h>
int kill(pid, int sig);
11,信号
对于收到一个信号后有三种处理办法:
》忽略这个信号
》捕获这个信号,使执行一段称为信号处理器的特殊代码。
》允许执行其默认操作
可利用kill函数发送信号。
除了SIGSTOP 和 SIGKILL,其它信号都可以被捕获或忽略。
pause函数挂起调用它的进程直到有任何信号到达。
#include <unistd.h>
int pause(void);
创建和设置信号集合,然后通过sigprocmask设置或修改当前信号掩码,设置要捕
获的信号,再向内核登记一个信号处理器(sigaction函数),最后第二个捕捉信
号。

创建,设置,查询一个信号集合
#include <signal.h>
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signum);
int sigdelset(sigset_t *set, int signum);
int sigismember(const sigset_t *set, int signum);
登记信号处理器
#include <signale.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
说明: how 可取值:
SIG_BLOCK --set包含其它要阻塞的信号
SIG_UNBLOCK -- set 包含要解除阻塞的信号
SIG_SETMASK --set包含新的信号掩码
   如果how为NULL,它被忽略。如果set为NULL,当前掩码保存在oldset中,如果
oldset为NULL,也被忽略。
#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct
sigaction *oldact);
// sigaction为signum所指定的信号设置信号处理器,sigaction结
构(act,oldact描述了信号的部署。在signal.h中有sigaction结构:
struct sigaction{
void (*sa_hundler)(int);
sigset_t sa_mask;
int sa_flag;
void (*sa_restorer)(void);
}
这个结构描述了当signum中的信号产生后要调用的处理器或者函数sa_hundler,
它也可被赋值SIG_DEF,引起signum默认动作发生,赋值SIG_IGN,使忽略这个信
号。
sa_mask定义了在执行处理器期間应该阻塞的其它信号集合的信号掩码。
sa_flags是修正sa_handler行为的掩码。可以为如下的值:
SA_NOCLDSTOP-- 进程忽略子进程产生的任何SIGSTOP,SIGSTP,SIGTTIN和SIGTTOU
信号
SA_ONESHOT 或 SA_RESETHAND--登记的自定义信号处理器只执行一次。在执行完
毕后,恢复信号的默认动作。
SA_RESTART--让可重启的系统调用起作用
SA_NOMASK或 SA_NODEFER--不避免在信号自己的处理器中接收信号本身。
对于函数中的sa_restorer元素,已经被废弃。

12,检测信号
sigpending使进程检测未决信号(当阻塞时被挂起的信号),然后可决定是忽略
它们还是递送它们。
#include <signal.h>
int sigpending(sigset_t *set);
未决信号集合在 set中返回,然后可以使用sigismember判断感兴趣的信号是否是
未决信号。

13,进程调度
#include <sched.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/resource.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);