(1)程序 program
被存放在磁盘中的可执行文件。
(2)进程 process
是程序的执行实例。每个进程具有独立的权限和职责,运行在各自的虚拟地址空间中。
进程之间不会相互影响,但可以进行通信。
(3)进程ID,process ID简称PID
非负整数,进程的数字标识符。
(1)“启动例程”被编译在main之前运行。
(2)收集命令行的参数,传递给main中的argc,argv。以及环境表envp。
(3)登记“终止函数”atexit()。
(1)正常终止
注意:
return和exit(),会刷新标准IO缓存,会自动调用终止函数。
_exit()和_Exit(),不刷新,也不调用。
(2)异常终止
(3)进程返回
(4)终止函数
#include
int atexit(void (*function)(void));
向内核登记终止函数,成功返回0,否则-1
linux中可用的资源resource如下:
RLIMIT_AS 进程可用的存储区大小
RLIMIT_CORE core文件最大字节数
RLIMIT_CPU CPU时间最大值
RLIMIT_DATA 数据段最大长度
RLIMIT_FSIZE 可创建文件的最大长度
RLIMIT_LOCKS 文件锁的最大数
RLIMIT_MEMLOCK使用mlock能否在存储器中锁定的最长字节数
RLIMIT_NOFILE 能打开的最大文件数
RLIMIT_NPROC 每个用户ID可拥有的最大子进程数
RLIMIT_RSS 最大驻内存集的字节长度
RLIMIT_STACK 栈的最大长度
#include
struct rlimit{
rlim_t rlim_cur;/*软件限制:当前限制*/
rlim_t rlim_max;/*硬件限制:当前限制可以达到的最大值*/
}
(1)获取进程的资源限制,存放在rlptr指向 的结构体中。成功返回0,失败非0。
int getrlimit(int resource , struct rlimit *rlptr);
(2)修改resource指定的资源限制,通过rlptr指向的结构体。成功返回0
int setlimit(int resource,const struct rlimie *rlptr);
可以查看到:进程ID(PID),进程的用户ID,进程状态STAT,进程的command等等。
系统当前的进程
就绪状态进程
PS命令的stat列 == R
等待事件发生
等待系统资源
PS命令的stat列 == S
PS命令的stat列 == T
进程终止或结束
在进程表项中仍有记录
PS命令的stat列 == Z
(1)处理内核中的工作
(2)处理当前进程
(3)选择进程(实时进程和普通进程)
(4)进程交换
(1)策略
(2)优先权
(3)实时优先权
(4)计数器
进程有很多的标识:
当前进程ID,实际用户ID,有效用户ID,用户组ID,父进程ID,进程组ID。
与此相关的函数:
#include
#include
pid_t getpid(void); //获取当前进程的ID标识
pid_t getppid(void); //获取父进程的ID标识
pid_t getpgrp(void); //获取当前进程所在的进程组ID标识。
pid_t getpgid(pid_t pid); //获取指定ID的进程所在的进程组ID标识。
uid_t getuid(void); //获取当前进程的 实际用户ID
uid_t geteuid(void); //获取当前进程的 有效用户ID
gid_t getgid(void); //获取当前进程的用户组ID
本文的重点内容。
fork函数
fork创建的新进程被称为子进程。该函数被调用一次,会返回两次。
返回两次的区别:
(1)在父进程里,返回的是 新子进程的进程ID。
(2)在新子进程里,返回的是0。因为子进程的数据段、堆、栈都是重新创建的。
(3)父和子进程的运行顺序,根据系统调度自动决定。
(4)子进程复制父进程的内存空间。
vfork函数
与fork类似,但是 子进程先行运行,且不复制父进程的内存空间。
子进程的继承属性
#include
2.函数
//list 列出每个字符参数
int execl(const char *pathname,const char *arg0, ... /*(char*)0*/);
//argv 字符数组
int execv(const char *pathname,char * const argv[]);
//list 列出每个字符参数,环境表
int execle(const char *pathname,const char *arg0, ... /*(char*)0,char* const envp[]*/);
//argv 字符数组,环境表
int execve(const char *pathname,char * const argv[],char* const envp[]);
//
int execlp(const char *pathname,const char *arg0, ... /*(char*)0*/);
//
int execvp(const char *pathname,char * const argv[]);
上述所有的返回:出错返回-1 ,成功不返回。
#include
2.函数
简化exec函数的使用,成功返回执行命令的状态,错误返回-1
int system(const char * command);
#include
#include
(1)等待子进程退出并回收。防止僵尸进程。成功返回子进程ID,出错返回-1。
pid_t wait(int *status);
(2)wait函数的非阻塞版本。成功返回子进程ID,出错返回-1。
pid_t waitpid(pid_t pid , int * status ,int options);
1)pid参数。
pid==-1 //等待任一子进程,功能和wait等效。
pid== 0 //等待 同进程组ID的任一子进程。
pid > 0 //等待指定的子进程
pid < -1 //等待 组ID等于(-pid)的任一子进程。
2)status参数。为空时,等待回收【任意状态】结束的子进程。不为空,则等待【指定状态】结束的子进程。
检查wait和waitpid函数返回终止状态的宏
WIFEXITED/WEXITSTATUS(status) //若为正常终止子进程返回的状态,则为真。
WIFSIGNALED/WTERMSIG(status) //若为异常终止子进程返回的状态,则为真。(接到一个不能捕捉的信号)
WIFSTOPED/WSTOPSIG(status) //若为当前暂停子进程返回的状态,则为真。
3)options参数。
WNOHANG //若由pid指定的子进程没有退出,则立即返回。waitpid不阻塞,返回值为0。
WUNTRACED //若某实现支持 作业控制,则有pid指定的任一子进程状态已暂停,其状态自暂停以来还没有报告过,则返回其状态。
前文已经给出:
#include
pid_t getpgrp(void); //获取当前进程所在的进程组ID标识。
pid_t getpgid(pid_t pid); //获取指定ID的进程所在的进程组ID标识。
#include
(1) 将进程加入到指定的进程组中。成功返回0,错误返回-1。
int setpgid(pid_t pid,pid_t pgid);
(2) pid参数为指定的进程号,pgid为进程组。
#include
(1)获取前台进程组ID。成功返回 前台进程组ID,错误返回-1。
pid_t tcgetpgrp(int fd);
(2)使用pgrpid,设置前台进程组ID
int tcsetpgrp(int fd,pid_t pgrpid);
(3)fd必须引用该会话的控制终端。0表示当前正在使用的终端。