进程:正在内存中运行的程序。Linux/Unix中用户可以同时运行多个进程
进程启动启动进程的两种手段:手动启动和调度启动(计划任务)
手动启动:可分为前台进程和后台进程。
调度启动:通过at或者cron启动,都是后台进程。
进程终止正常终止:从main返回;调用exit函数;调用 _exit系统调用。
异常终止:被信号终止;调用abort,产生SIGABRT信号。
进程标识每一个进程都有一个唯一的标识:PID,其为非负整数。
三个特殊进程:
PID=0的调度进程:内核的一部分,又称交换进程或者系统进程。
PID=1的init进程:是内核启动并运行的第一个用户进程。负责对系统进行初始化,并将系统引导到某个状态。init进程不能被终止!
PID=2的kthreadd内核进程:是一个内核线程,负责执行后台操作。
进程状态运行态:在CPU中运行或就绪的状态。包括:内核运行态,用户运行态,就绪态。
可中断睡眠态:处在此状态的进程,系统不会调度该进程执行,当系统产生一个中断,或释放其正在等待的资源,或进程收到一个信号,都可以被唤醒而进入就绪态。
不可中断睡眠态:不是指不响应外部的硬件中断,而是指进程不响应异步信号,只有wake_up()显式的唤醒。
暂停态:当进程接收到SIGSTOP、SIGTSTP、SIGTTIN或SIGTTOU信号时会进入暂停态,可向其发送SIGCONT信号唤醒。
僵尸态:当进程已经停止运行,但其父亲没有响应其信号,则该进程处于僵死态。
PCB——进程控制块内核通过PCB对进程执行控制和管理。Linux中PCB由task_struct结构体定义。
PCB包含信息:
PID:进程标识
进程状态
进程资源清单:包括拥有的设备、打开的文件等
进程的优先级
CPU现场保护
PPID(父进程的PID),用户ID,组ID等其他信息
获取PID:
#include进程创建 forkpid_t getpid(); //获取当前进程的PID pid_t getppid(); //获取当前进程的父进程的PID
Linux中,程序通过fork或者vfork 系统调用来创建一个进程。
若是返回值PID小于0,则表示进程创建失败。
fork调用是一个双返回的函数,在父进程中返回新创建的子进程PID,在子进程中返回0。
pid_t fork();
pid_t vfork();//vfork()需与execve()或者exit系统调用配合使用。子进程先运行,父进程挂起直到子进程调用exec或者_exit,之后的父子进程执行顺序无限制。
vfork建立的子进程与父进程共享数据段。
子进程继承父进程的属性有:已打开的文件描述符,实际UID、GID和有效UID、GID,控制终端,当前工作目录,根目录,文件创建掩码umask,环境,资源限制。
#includeexec函数族#include #include #include int main(){ pid_t pid; char *message; int n; pid=fork(); if(pid<0){//进程创建失败 perror("fork failed"); exit(1); } if(pid==0){//执行子进程 message="This is the childn"; n=3; } else {//执行父进程 message="This is the fathern"; n=6; } for(;i>0;--i){ printf(message); sleep(1); } return 0; } -----output------ This is the child This is the father This is the father This is the child This is the father This is the child This is the father This is the father This is the father
同system,用指定的程序启动一个进程。
与system的不同之处:system启动一个shell来启动新的进程;exec用新进程完全替换旧进程,包括进程的正文、数据、堆、栈段,并且exec调用前后进程ID不变。
格式:
#includeint execl(char *path, char *arg, …);//返回-1:出错 //参数逐个加入 int execv( char *path, char *argv[]); //参数以数组形式加入 int execle(char *path, char *arg, …, char *envp[]); int execve(char *path, char *argv[], char *envp[]);//仅此为系统调用函数 //+e,添加一个环境变量数组 int execlp(char *file, char *arg, …); int execvp(char *file, char *argv[]); //+p,给出命令名,自行查找命令位置并执行 execl("/bin/ls","ls","-l",0);//调用ls程序,显示当前目录下文件信息。
path:待运行程序的全路径名
file:程序(命令)名称,在PATH路径上搜索
arg, … :可选的多个命令参数,要求最后一个必须是NULL ; 为了方便第一个参数要求为执行程序的名称。
argv:命令参数指针数组,要求同arg,…
envp:传递给运行程序的环境变量指针数组;若没有此参数,启动进程的环境变量则继承自当前shell,否则为该数组中的变量。
僵尸进程:一个已经终止运行、但其父进程尚未对其进行善后处理(释放其PCB块)的进程
孤儿进程:fork创建的子进程,在父进程已经结束后仍在运行。很快被init进程回收。
进程等待#include#include pid_t wait(int *status);//等待任意子进程,若没有则返回-1 pid_t waitpid(int pid,int *status,int options);//等待特定进程,pid=-1则为任意进程
作用:等待子进程结束,并阻塞父进程。返回时将子进程的返回码保存到status中,并返回等到的结束的子进程的PID。
options:0或者WNOHANG;WNOHANG表示指定子进程的退出状态不能立即得到,但不阻塞并返回0.
守护进程WIFSIGNALED(status):若是因未捕获信号而退出则该宏为非0;
WTERMSIG(status):若因未捕获信号而退出,则通过该宏获得信号值;
WIFSTOPPED(status):若子进程意外终止,则该宏为非0;
WSTOPSIG(status):若因意外终止,则该宏获得引起子进程终止的信号值。
守护(服务)进程(daemon):运行在后台,独立于控制台并且周期性的执行某种任务或等待处理某些发生的事件。
常见守护进程:
init:系统守护进程,PID为1,负责启动各运行层次特定的系统服务;
keventd:为内核定时任务提供上下文;
portmap:端口映射,提供RPC程序号映射为网络端口号;
编写要点
-
创建子进程,终止父进程;
pid=fork(); if(pid>0) exit(0);//终止父进程
-
在子进程中创建新的会话;
-
改变工作目录;
-
重设文件创建掩码
-
关闭文件描述符
for(i=0;i
创建守护进程
#include#include #include void daemonize(){ pid_t pid; if((pid=fork())<0){ perror("fork"); exit(1); } else if(pid!=0) exit(0);//parent setsid();//创建新的对话 if(chdir("/")<0){ perror("chdir"); exit(1); } //标准输入输出,错误输出重定向到/dev/null close(0); open("/dev/null",O_RDWR); dup2(0,1); dup2(0,2); }
相关函数
系统日志文件操作pid_t setsid(void);//创建新会话并设置进程组ID,创建的新进程是新进程组和会话组的leader。头文件:unistd.h
chdir(char *path);//改变工作目录,一般为"/“或者”/tmp".
umask(mode_t mask);//一般设为umask(0)
int dup(int fno);//将文件描述符复制到一个可用的描述符
int dup2(int oldfno, int newfno);//让newfno和oldfno描述符共享同一个文件表项。oldfno:必须是一个已打开的文件描述符
两个函数的结果都是将新的描述符和旧的描述符指向相同的文件。
dup2常用于实现文件的重定向
#includevoid openlog(char *indent,int option,int facility); void syslog(int priority,char *format,...); void closelog();//关闭日志
indent:输出日志时加的前缀,默认为程序名称;
option:LOG_PID日志信息添加PID;LOG_cons不能写日志时直接输出到控制台
facility:日志种类:LOG_DAEMON、LOG_CRON
priority:日志信息或等级:LOG_INFO,LOG_ERR,LOG_DEBUG
format:字符串格式,同printf。
t option,int facility);
void syslog(int priority,char *format,…);
void closelog();//关闭日志
indent:输出日志时加的前缀,默认为程序名称; option:LOG_PID日志信息添加PID;LOG_cons不能写日志时直接输出到控制台 facility:日志种类:LOG_DAEMON、LOG_CRON priority:日志信息或等级:LOG_INFO,LOG_ERR,LOG_DEBUG format:字符串格式,同printf。



