进程控制

    一个人不可能丧失一个他并不拥有的东西

                                                              --------马克。奥勒留

  时间和空间是计算机的两个重要的基本概念,操作系统将这两个概念分为大家熟悉的进程和文件,随便说下在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 语言中的内存分配,可以参考我写的第一篇

posted @ 2013-04-09 13:48  bug_yao  阅读(271)  评论(0)    收藏  举报