系统编程-进程

什么是程序?什么是进程?
程序是通过gcc xx.c-o pro,在磁盘中生产的pro文件,进程是程序正在运行
可以通过或者top或者ps -aux | grep配合使用查看某一个进程

进程标识符
每一个进程都有一个非负整数表示的唯一的ID------pid
pid=0:称为交换进程
pid=1:init进程——系统初始化
我们可以通过getpid()函数获取自身的进程标识符,getppid()获取父进程的进程标识符,父进程使用getppid()获取的进程标识就是shell进程。

创建子进程
系统编程-进程
fork函数作用:创建一个进程,fork成功调用,返回两次
返回值:0,代表当前进程为子进程
返回值:非负数,代表当前进程为父进程
返回值:-1,代表调用失败

父子进程fork()之后有哪些相同不同?
相同:全局变量,data,text,堆,栈,环境变量。用户ID,宿主目录,进程工作目录,信号处理方式。
不同:进程ID,fork()返回值,父进程ID,进程运行时间,闹钟(定时器),未决信号集。
父子进程间遵循读时共享写时拷贝的原则,目的为了节省内存开销。

fork创建一个子进程的目的:
1、一个父进程希望可以多一个同样的自己来同时执行不同的代码。最常见的就是父进程等待客户端的服务请求,当请求到达时,父进程调用fork,让子进程来处理这个请求,父进程继续等待下一个请求
2、一个进程要执行一个不同的程序,通常调用exec函数

创建进程也可以用vfork函数来创建,那它跟fork函数的区别在于:
1、vfork直接使用父进程的存储空间,不拷贝
2、vfork保证子进程先运行,当子进程调用exit退出后,父进程再执行

进程退出
正常退出:
1.main函数调用return
2.进程调用exit(),标准c库语言
3.进程调用_exit()或者_Exit,属于系统调用(补充:进程最后一个线程返回,最后一个线程调用pthread_exit())

异常退出:
1.调用abort
2.当进程收到某些信号,如ctrl+c
3.最后一个线程对取消(cancellation)请求作出响应

如果我们想要实现终止进程能够通知其父进程它是如何终止,可以通过三个终止函数(exit、_exit、_Exit)将其退出状态作为参数传送给函数,那么禁止进程的父进程用wait或者waitpid函数取得终止状态
系统编程-进程
系统编程-进程
父进程等待子进程退出,并收集子进程的退出状态,如果子进程退出状态不被收集,会成为僵尸进程
系统编程-进程
wait函数作用:如果所有所有子进程都还在运行,则阻塞;如果一个子进程已终止,正等待父进程获取其终止状态,则取得该子进程的终止状态立即返回;如果没有任何子进程,则立即出错返回

status参数:是一个整数型指针,非空:子进程退出状态放在它所指向的地址中;空:不关心退出状态

pid参数:
pid== -1,代表着等待任何一子进程,
pid>0,代表等待其进程ID与pid相等的子进程
pid==0,代表其组ID等于调用进程组ID的任何一子进程
pid<-1,代表着其组ID等于pid绝对值的任一进程

exec族函数
我们在fork函数创建新进程后,经常会在新进程中调用exec函数去执行另外一个程序。当进程调用exec函数时,该进程被完全替换为新程序。
注:因为调用exec函数并不创建新进程,所以前后的ID并没有改变。
系统编程-进程
exec功能:在调用进程内部执行一个可执行程序。
exec函数参数说明:
path:可执行文件的路径名称
arg:可执行程序所带的参数,第一个参数为可执行文件名字,没有带路径且arg必须以NULL结束
file:如果参数file中包含/,则为路径名,没有就按环境变量,在所指定的目录下搜素可执行文件
返回值:如果调用成功则加载新的程序从启动代码开始执行,不在返回。如果调用出错则返回-1

命名理解
这些函数原型看起很容易混淆,但只要掌握了规律就很好记
l(list):表示参数采用列表;
v(vector):参数用数组;
p(path):有p自动搜索环境变量PATH;
e(env):表示自己维护环境变量

前三个含有字母l,后三个含有字母v,带有l的代表参数列表一一列举在函数的参数中,并要求以NULL结尾;带有v的代表参数列表放在一个以NULL结尾的指针数组之中(即第二个参数)。
带有字母p的代表2个以p结尾的函数execlp和execvp,看起来,和execl与execv的差别很小,事实也如此,它们的区别从第一个参数名可以看出:除 execlp和execvp之外的4个函数都要求,它们的第1个参数path必须是一个完整的路径,如”/bin/ls”;而execlp和execvp 的第1个参数file可以仅仅只是一个文件名,如”ls”,这两个函数可以自动到环境变量PATH指定的目录里去查找。
带有字母e的是指给可执行文件指定环境变量。在全部6个函数中,只有execle和execve使用了char *envp[]传递环境变量,其它的4个函数都没有这个参数,这并不意味着它们不传递环境变量,这4个函数将把默认的环境变量不做任何修改地传给被执行的应用程序。而execle和execve用指定的环境变量去替代默认的那些。

system函数
system与execl族函数一样用于执行新的进程,与excel函数相比,system函数不需要带路径。
系统编程-进程system()函数返回值: 成功,则返回进程的状态值; 当sh不能执行时,返回127; 失败返回-1

system()函数执行了三步操作:
1.fork一个子进程;

2.在子进程中调用exec函数去执行command;

3.在父进程中调用wait去等待子进程结束。 对于fork失败,system()函数返回-1。 如果exec执行成功,也即command顺利执行完毕,则返回command通过exit或return返回的值。 (注意,command顺利执行不代表执行成功,比如command:“rm debuglog.txt”,不管文件存不存在该command都顺利执行了) 如果exec执行失败,也即command没有顺利执行,比如被信号中断,或者command命令根本不存在,system()函数返回127. 如果command为NULL,则system()函数返回非0值,一般为1.

popen函数
创建一个管道,然后fork创建一个进程。由于管道具有单向性质,所以参数type只能指定为读或写,不能同时指定。函数返回的值也相应的只读或只写。
系统编程-进程
popen函数的返回值是正常I/O流。
比system相比:可以获取运行的输出结果