目录
1.概念
从用户角度:进程就是一个正在运行中的程序。
查看进程:ps -aut|grep +进程蕴含信息
fork创建的进程,代码由父子进程共享,写时复制,内核将这些区域定义为只读,需要修改时再复制
2.类型
僵尸进程
子进程退出状态不被收集,变成僵死进程 Z+ S+表示正在运行
孤儿进程
父进程如果不等待子进程退出,在子进程之前就结束了自己的“生命”,此时子进程叫做孤儿进程
Linux避免系统存在过多孤儿进程,init进程(返回1)收留孤儿进程,变成孤儿进程的父进程
3.进程标识符,类型:pid_t 。 (=pid) ;
每个进程都有一个非负整数表示的唯一ID,叫做pid,类似身份证
Pid=0: 称为交换进程(swapper)作用:进程调度
Pid=1:init进程 ,作用 :系统初始化
4.API
4.1 进程创建 :vfork()
它从已存在的进程中创建一个新进程。新进程为子进程,而原进程为父进程。
fork运行后,父子进程共享fork往后的代码,共享数据段变量、堆栈。当父进程或者子进程,需要改变变量时,内核复制一个变量给予修改,原变量不变。
先后:没有先后,可同时运行。先后取决于进程调度
返回
返回值非负数(子进程ID) | 代表当前进程为父进程 |
返回值为0(通过getppid调取父进程ID) | 代表当前进程是子进程 |
创建失败 | 返回-1 |
vfork 直接使用父进程存储空间,不拷贝。
vfork保证子进程先运行,当子进程调用exit退出后,父进程才执行。
4.2 查看进程
getpid()
查看当前程序的进程ID
getppid()
查看当前程序的父进程ID
4.3.收回子进程 : wait
pit_t wait(int *status)
函数功能
●如果其所有子进程都还在运行,则阻塞。s+
.如果一个子进程已终止,正等待父进程获取其终止状态,则取得该子进程的终止状态立即返回。
●如果它没有任何子进程,则立即出错返回-1
如果先终止父进程,子进程将继续正常进行,只是它将由init进程(PID 1)继承,当子进程终止时,init进程捕获这个状态
返回
wait会返回被收集的子进程的进程ID,存在status中,但是要用WEXITSTATUS解析才能正常显示。exit(3)_ 正常退出:*status=3 异常退出 *status!=3,注意要用WEXITSTATUS解析才能正常显示。是否正常退出用WIFEXITED(status)!=0检测,异常=0
-1:没有子程序,wait在fork之前
空:不关心退出状态
status相关操作
WIFEXITED(status) | 这个宏用来指出子进程是否为正常退出的,如果是,它会返回一个非零值。 |
WEXITSTATUS(status) | 当WIFEXITED返回非零值时,可解析子进程的返回值,传送给exit.- exit或 Exit参数的低8位 |
WIFSIGNALED (status ) | 若为异常共止子进程返回的状态,则为真(接到一个不捕捉的信号)。对于这种情况,可执行WTERMSIG (starus), 取使子进程线止的信号编号。另外,有些实现(非Single UNIX Specifcation) 定义宏WCOREDUMP (stanes), 若已产生终止进程的core文件,则它返回真 |
WIFSTOPPED (stomus) | 若为当前暂停子进程的返回的状态,则为真。对于这种情况,可执行WSTOPSIG(staus),取使子进程暂停的信号编号 |
WIFCONTINUED (status) | 若在作业控制暂停后已经继续的子进程返回了状态,则为真。(POSIX.I的XSI扩展:仅用于waitpid.) |
4.4.收回子进程 : waitpid
pid_t waitpid(pid_t pid, int *status, int options)
函数功能
●如果其所有子进程都还在运行,则阻塞。可以不阻塞
.如果一个子进程已终止,正等待父进程获取其终止状态,则取得该子进程的终止状态立即返回。
●如果它没有任何子进程,则立即出错返回
如果先终止父进程,子进程将继续正常进行,只是它将由init进程(PID 1)继承,当子进程终止时,init进程捕获这个状态
返回
wait会返回被收集的子进程的进程ID
-1:没有子程序,wait在fork之前
空:不关心退出状态
pid
pid>0时 | 只等待进程ID等于pid的子进程,不管其它已经有多少子进程运行结束退出了,只要指定的子进程还没有结束,waitpid就会一直等下去。 |
pid=-1 | 等待任一个子进程退出,没有任何限制,此时waitpid和wait的作用一模一样。 |
pid=0 | 等待同一个进程组中的任何子进程,如果子进程已经加入了别的进程组,waitpid不会对它做任何理睬。 |
pid<-1 | 等待一个指定进程组中的任何子进程,这个进程组的ID等于pid的绝对值 |
options
WCONTINUED | 若实现支持作业控制。那么由pid指定的任一子进程在暂停后已经继续, 但其状态尚未报告,则返回其状态(POSIX.1的XSI扩展) |
WNOHANG | 若由pid指定的子进程并不是立即可用的,则waitpid不阻塞,此时其返回值为0 |
WUNTRACED | 若某实现支持作业控制,而由pid指定的任-“ 子进程已处于暂停状态,井且其状态自暂停以来还未报告过,则返回其状态。WIFSTOPPED宏确定返回值是否对应于一个暂停子进程 |
status相关操作
WIFEXITED(status) | 这个宏用来指出子进程是否为正常退出的,如果是,它会返回一个非零值。 |
WEXITSTATUS(status) | 当WIFEXITED返回非零值时,可解析子进程的返回值,传送给exit.- exit或 Exit参数的低8位 |
WIFSIGNALED (status ) | 若为异常共止子进程返回的状态,则为真(接到一个不捕捉的信号)。对于这种情况,可执行WTERMSIG (starus), 取使子进程线止的信号编号。另外,有些实现(非Single UNIX Specifcation) 定义宏WCOREDUMP (stanes), 若已产生终止进程的core文件,则它返回真 |
WIFSTOPPED (stomus) | 若为当前暂停子进程的返回的状态,则为真。对于这种情况,可执行WSTOPSIG(staus),取使子进程暂停的信号编号 |
WIFCONTINUED (status) | 若在作业控制暂停后已经继续的子进程返回了状态,则为真。(POSIX.I的XSI扩展:仅用于waitpid.) |
注意:调用WNOHANG不阻塞时,不接受子程序的返回,变僵死程序
4.5.退出
正常退出
Main函数调用return
进程调用exit(),标准c库 0 1 2 ,会冲刷缓冲区
进程调用_exit()或者_Exit(),属于系统调用 直接退出
进程最后一个线程返回
最后一个线程调用pthread_exit
异常退出
调用abort,等于放弃当前进程
当进程收到某些信号时,如ctrl+C,等于强制停止
最后一个线程对取消(cancellation)请求做出响应
概念
任何进程如何终止的,最后内核都会执行同一段代码,这段代码会为相应进程关闭所有打开的描述符,释放相应的存储器
对上述任意-种终止情形、 我们都希望终止进程能够通知其父进程它是如何终止的。对于三个终止函数(exit、_ exit和_ Exit), 实现这一点的方法是,将其退出状态(exit status),作为参数传送给函数。
在异常终止情况下,内核(不是进程本身)产生一个指示其异常终止原因的终止状态(termination status)。 在任意一 种情况下,该终止进程的父进程都能用wait或waitpid函数(在下一节说明)取得其终止状态。
exec为替换进程,不执行下面内容,而 system,可以执行以下内容
4.6.进程替换和中断
(1) 进程 “替换” exec族 linux进程---exec族函数(execl, execlp, execle, execv, execvp, execvpe)_牛仔的blog-CSDN博客_execleexec族函数函数的作用:我们用fork函数创建新进程后,经常会在新进程中调用exec函数去执行另外一个程序。当进程调用exec函数时,该进程被完全替换为新程序。因为调用exec函数并不创建新进程,所以前后进程的ID并没有改变。exec族函数定义: 可以通过这个网站查询:linux函数查询 功能: 在调用进程内部执行一个可执行文件。可执行文件既可以是二进制文件,也可以是任何Linux下可执https://blog.csdn.net/u014530704/article/details/73848573
功能:
我们用fork函数创建新进程后,经常会在新进程中调用exec函数去执行另外一个程序。当进程调用exec函数时,该进程被完全替换为新程序。因为调用exec函数并不创建新进程,所以前后进程的ID并没有改变
在调用进程内部执行一个可执行文件。可执行文件既可以是二进制文件,也可以是任何Linux下可执行的脚本文件。
API
execl | int execl(const char *path, const char *arg, ...); | 通过路径,找到可执行文件(第一个参数),然后加上后面传入的参数 运行程序 ls ,-l ,NULL |
execlp | int execlp(const char *file, const char *arg, ...); | 不同:file可以为路径(包含/),也可以为可执行文件名字(第一参数),为名字时通过环境变量PATH,找到文件执行 |
execle | int execle(const char *path, const char *arg,..., char * const envp[]); | |
execv | int execv(const char *path, char *const argv[]); | 应先构造一个指向各参数的指针数组,然后将该数组的地址作为这些函数的参数。 |
execvp | int execvp(const char *file, char *const argv[]); | 应先构造一个指向各参数的指针数组,然后将该数组的地址作为这些函数的参数。 |
execvpe | int execvpe(const char *file, char *const argv[],char *const envp[]); |
参数
path:可执行文件的路径名字 ,直接加入路径,不需要加 . 。‘ . ’代表缺省的路径,这里无缺省
arg:可执行程序所带的参数,第一个参数为可执行文件名字,第二个及以后的参数为运行这个程序时跟在命令行的参数。没有带路径且arg必须以NULL结束
例: execl("/bin/rm","rm","-r",NULL) 替换为了 rm 文件 = 命令行的 "rm -r"
例:char *argv[] = {"ps","-l",NULL}; execvp("ps",argv)
file:如果参数file中包含/,则就将其视为路径名,否则就按 PATH环境变量,在它所指定的各目录中搜寻可执行文件。
不同:file可以为路径,也可以为可执行文件名字(第一参数),为名字时通过环境变量PATH,找到文件执行
返回
exec函数族的函数执行成功-----不会返回
调用失败时,会设置errno并返回 “-1” ,然后从原程序的调用点接着往下执行。
记忆
l : 使用参数列表
execl、execlp、execle
p:使用文件名,并从PATH环境进行寻找可执行文件
execlp、execvp、execvpe
v不带l:应先构造一个指向各参数的指针数组,然后将该数组的地址作为这些函数的参数。
execv、execvp、execve
e:多了envp[]数组,使用新的环境变量代替调用进程的环境变量
execle、execvpe
进程中,加入运行其他进程
4.7 system
int system(const char * string); ” a.out“
可直接写入路径或者命令参数
返回
成功,则返回进程的状态值;
当sh不能执行时,返回127;
失败返回-1;
4.8 popen
FILE * popen(const char *command , const char *type );
自己创建进程,运行命令(command),将运行结果或者是运行信息,通过创建的管道发送到文件中,返回这个文件的描述符,再pclose关闭管道,可以用fread()读取结果
type
type的可选值为“w”或“r”,代表可读与可写。代表popen返回的文件的属性。
w 可读,标准输入
r 可写,标准输出
返回 ;文件描述符
自己创建进程,运行命令
注意:system 可以返回代码段,运行下面的代码,popen可以返回输出结果
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
int main(){
pid_t pid;
int cen=0;
int stuta=0;
pid=fork();
if(pid>0){
wait(&stuta);
printf("stuta==%d\n",WEXITSTATUS(stuta));
while(1){
printf("This is father ID:%d\n",getpid());
sleep(1);
}
}else{
execl("/bin/ls","ls",NULL,NULL);// open格式 ./aaa ‘ . ‘可以看作缺省路径
execl("./bin/ls","ls","NULL",NULL);// 此处没有缺省。不需要
while(1){
printf("This is son ID:%d cen=%d\n",getpid(),cen);
sleep(1);
cen++;
if(cen==5){
a=system("ls");
if(a==-1)
printf("filed\n");
execl("/bin/ls","ls",NULL,NULL);
exit(2);
}
}
}
return 0;
}
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
int main(){
char p[1024]={0};
FILE *fp=NULL;
fp=popen("ls","r");
int nread=fread(p,1,1024,fp);
printf("The news is %d byte and %s\n",nread,p);
pclose(fp);
return 0;
}