进程控制
一个人不可能丧失一个他并不拥有的东西
--------马克。奥勒留
时间和空间是计算机的两个重要的基本概念,操作系统将这两个概念分为大家熟悉的进程和文件,随便说下在linux 下是一切设备皆文件.神马U盘,磁盘都是以文件的形式读取的.
好多书上介绍进程的一开始就是介绍进程和程序的区别,程序一堆代码,官方说法是可以运行的二进制文件,把文件加载到内存就成进程了.id就像进程的身份证号,一一对应.一个程序倒是可以对应多个进程,不是程序加载到内存变成进程,为啥可以对应多个进程,他可以加载多次,例如可以打开多个shell,.在shell中可以用ps查看用户的进程. pid 就是进程标号,TTY是控制台,CMD 就是我目前运行的两个程序,一个是我的bashshell ,另一个就是我查看进程的进程,上一篇有个结果没给大家贴出运行结果不是我懒,是用的window中不好显示二进制文件的大小,顺便给大家介绍个linux下的截图工具,scrort,用
scrot -s rectangle.png命令即可.
说说进程中重要的 Id 和获取方式吧。pid_t pid , ppid, uid,euid, gid,egid; pid_t 是个无符号整型,unsigned int ;
pid = getpid(); //进程ID
ppid = getppid(); //父进程ID
uid = getuid(); // 用户ID
euid = geteuid(); //有效用户Id
gid = getgid(); //组Id
egid = getegid(); // 有效组ID ;
对进程来说流程就是创建,操作,最后注销而已,就像介绍一个函数,列出头文件,原型,返回值。
创建:头文件 #include<unistd.h>
函数原型 pid_t fork(void);
函数返回值 ;当是父进程时 fork()返回子进程的ID ;
当时子进程时fork()返回0,因为0是系统进程的ID ,子进程的Id 永远不会是0,所以用0表示子进程;
错误返回 -1;
创建的子进程完全复制了父进程的地址空间,代码段是共享的,其他是完全独立的,也就是子进程改变了数据段的内容不会影响父进程,子进程和父进程优先级是一样的,也就是说谁也可能先执行。再给大家介绍一个函数Vfork();头文件和fork一样,这和创建的子进程和父进程完全一样,修改了子进程的数据段,父进程也会改变,并且子进程永远执行在父进程前面,这里注意的是函数里进来别调用vfork因为调用完了,子进程执行完了,函数就返回了,当执行了父进程时当时的内存地址已经是别的函数了,就会返回段错误,也就是内存访问错误,
谈到fork(),就必须谈到exec();exec()就是加载程序到当前的地址空间,这是一系列函数,要是具体将他们的参数时,那还的在讲上一节环境变量;妈妈说学校要站在别人的肩膀上,这样就可以抄别人的作业了,所以我给大家找了一片还算详细文章 http://blog.sina.com.cn/s/blog_759803690101aqgs.html 要是这时候在不加上一段代码来说这两个函数的关系的话,我就太懒了。
#include<stdio.h> #include<unistd.h> #include<stdlib.h> int main (void) { pid_t pid; pid = fork(); if( pid < 0) { printf("fail to fork \n"); exit(1); } else if(pid == 0) { if( (execv("./hello",NULL)) == -1) { printf("fail to exec \n"); exit(1); } printf ("会不会到这啊!!!不会的 \n"); //exec 函数族执行完退出一层,不会执行后面的,个人见解 } else { sleep(2); printf("i am parent \n"); } return 0; }
这就是运行结果,先运行的。/hello程序。fork()创建一个进程,exec()加载程序,就是这样。
该说说进程见关系操作了,在这里唠叨一下,前面是写了2遍,因为系统突然崩溃了,我很郁闷,一向以稳定而著名的linux在我手上宕机了,当然我用的不是LTS(长期支持版本),用的是最新的也就是说不是稳定的版本,建议大家用内核是偶数的版本,以前用的是稳定版本没出现过问题,这个就经常死机了,也懒得换,等到忍无可忍再说吧。
先说下僵尸进程,就是创建的子进程只关闭,不回收,这样系统中没有任何进程资源但占了个Id ,就是占个茅坑不拉屎,尽管系统中有很多茅坑,但是多了Id 用完了就出现问题了,还是给大家说下官方说法吧,摘自百度进程百科:UNIX 系统中,一个进程结束了,但是他的父进程没 有等待(调用wait / waitpid)他, 那么他将变成一个僵尸进程。 但是如果该进程的父进程已经先结束了,那么该进程就不会变成僵尸进程, 因为每个进程结束的时候,系统都会扫描当前系统中所运行的所有进程, 看有没有哪个进程是刚刚结束的这个进程的子进程,如果是的话,就由Init 来接管他,成为他的父进程。也就是说解决僵尸进程有2个方法,一是父进程调用wait();waitpid();
2是父进程先结束,把子进程给init,他总是自动调用wait()。说说这两个函数:
头文件:#include<sys/wait.h> 状态 判断宏 取值宏
函数原型: pid_t wait(int *statloc) 正常结束 WIFEXITED(status) WEXITSTATUS(status)
返回值: 没有子进程返回 -1,有则返回进程ID 异常终止 WIFSIGALED(status) WTERMSIG(status)
暂停 WIFSTOPPED(status) WSTOPSIG(status)
函数原型 pid_t wait_pid(pid_t pid , int *statloc,int option) option 取值 WCONTINUED 暂停后继续执行,返回其状态
返回值:出错返回-1 WNOHANG 进程未结束不阻塞函数直接返回。
WUNTRACED 暂停返回状态。
该值可以为0;
解释下int *statloc 这是把进程结束的信息保存到这里。NULL 值表示不关心。
一般形式 : wait(&statius); wait(NULL);
waitpid(childpid,&statius,0);
下面用两方式解决分别是用wait 和先关闭父进程来解决僵尸进程。
#include<stdio.h> #include<unistd.h> #include<stdlib.h> int main() { pid_t pid; int status; pid = fork(); if(pid < 0) { printf("fail to fork"); exit(1); } else if(pid == 0) { printf(" child done \n"); sleep(2); printf("child xingle \n"); exit(0); } else { printf("parent \n"); sleep(15); if (wait(&status) == -1) { perror("fail to wait \n"); exit(1); } printf("%d \n",status); exit(0); } return 0; }
先是僵尸进程后来就没了。。有图有真相。。Z 就是僵尸进程,最后调用了wait()就消失了。
#include<stdio.h> #include<stdlib.h> #include<unistd.h> int main() { pid_t pid; pid = fork(); if(pid < 0) { perror("eror fork \n"); exit(1); } else if (pid == 0) { //sleep(1); printf("我是儿子 \n"); pid = fork(); if(pid < 0) { perror("error fork2 \n"); exit(1); } else if(pid == 0) { printf("我是孙子 \n"); sleep(15); printf(" 孙子 xingle \n"); exit(0); } else { printf("我是儿子爱爱爱 \n"); exit(0); } } else //sleep(20); printf("我是爸爸啊啊 \n"); return 0;
if (system("ls >>tmp.txt") == -1)
{
perror("error system \n");
exit(1);
} }
当儿子先结束,孙子进程就是由init收养,不会是僵尸进程。
最后无聊给大家加了个system()函数头文件是#include<stdlib.h>,如何用已经有范例了。
宁愿听课,不愿看书,宁愿看书,不愿敲代码,宁愿敲代码不愿写这些东西,一个比一个费劲。当然最重要的是习不是学。。。
附加 : 进程这块主要区别下子进程和父进程的区别,子进程复制了父进程了什么,这块不是很清的话,你进程会写的一塌糊涂,哈哈哈,,http://www.cnblogs.com/zhangchaoyang/articles/2317420.html 这之前要知道C 语言中的内存分配,可以参考我写的第一篇
浙公网安备 33010602011771号