Unix下的进程管理

进程的概述

进程的概念

  直观点说,保存在硬盘上的程序运行以后,会在内存空间里形成一个独立的内存体,这个内存体有自己的地址空间,有自己的堆,上级挂靠单位是操作系统。操作系统会以进程为单位,分配系统资源,所以我们也说,进程是资源分配的最小单位。

进程调度中的三种状态

  • 运行:当一个进程在处理机上运行时,则称该进程处于运行状态。处于此状态的进程的数目小于等于处理器的数目,对于单处理机系统,处于运行状态的进程只有一个。在没有其他进程可以执行时(如所有进程都在阻塞状态),通常会自动执行系统的空闲进程。
  • 就绪:当一个进程获得了除处理机以外的一切所需资源,一旦得到处理机即可运行,则称此进程处于就绪状态。就绪进程可以按多个优先级来划分队列。例如,当一个进程由于时间片用完而进入就绪状态时,排入低优先级队列;当进程由I/O操作完成而进入就绪状态时,排入高优先级队列。
  • 阻塞:也称为等待或睡眠状态,一个进程正在等待某一事件发生(例如请求I/O而等待I/O完成等)而暂时停止运行,这时即使把处理机分配给进程也无法运行,故称该进程处于阻塞状态。

UNIX中的进程控制

创建新进程

1.进程标识符

  每个进程都有一个非负整形表示唯一的ID,因此用来作为进程的标识符。unix系统的ID为0的进程通常是调度进程,常常被称为交换进程。ID为1的进程为init进程,在自举结束的时候由内核调用。init进程绝不会终止,虽然它是一个用户进程,但是它以超级用户的特权运行,后面会介绍init对于孤儿进程的领养。

  以下方法来获得标识符

pid_t getpid();      //返回调用进程的pid
pid_t getppid();     //返回调用进程的父进程pid

2.创建新进程

  创建进程可以通过下面两个函数进行创建

pid_t fork();    //子进程中返回0,父进程中返回子进程pid
pid_t vfork();   //子进程中返回0,父进程中返回子进程pid

  两者是有区别的,这就要从创建一个进程的过程中对于父进程相关环境的处理说起了。

  两个函数都是调用一次之后会返回两次,对于子进程而言返回值是0,在父进程中又返回的是子进程的pid。这样做的原因也比较好理解:父进程拥有很多子进程,但是没有函数可以获得子进程的pid,所以在分配的时候就必须将子进程的ID进行记录。

  两者的不同在于:

  • fork之后,子进程是父进程的副本,子进程获得父进程数据空间、堆和栈的拷贝。父子进程之间并不共享这些存储空间部分,但是父子进程共享正文段。但是现在很多采用了写时复制技术,也就是说fork之后父子进程还是先共享这些存储空间部分,只有当子进程试图去修改的时候才会拷贝一份。
  • vfork的设计本身就是为了创建进程之后让进程立马调用exec去执行一个新程序,因此vfork之后子进程与父进程还是共享着存储空间,在调用exec之前,子进程还是在父进程的空间中运行。除此之外,vfork和fork的另一个不同之处在于vfork之后,保证子进程先执行

      

      下面的程序揭示了两者之间的区别

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int glob = 6;
char buf[] = "a write to stdout\n";

int main()
{
    int var;
    pid_t pid;

    var = 88;
    if(write(STDOUT_FILENO, buf, sizeof(buf)-1) != sizeof(buf)-1);
        exit(-1);
    printf("before fork\n");

    if((pid = fork()) < 0)
    {
        printf("fork error\n");
        exit(-1);
    }
    else if(pid == 0)
    {
        //child
        glob++;
        var++;
    }
    else
    {
        //parent
        //父进程休眠2s,让子进程先执行
        sleep(2);
    }
    printf("pid = %d, glob = %d, bar = %d\n", getpid(), glob, var);
    exit(0);
}

执行程序的结果如下:

./a.out

a write to stdout

before fork

pid = 430, glob = 7, var = 89

pid = 429, glob = 6, var = 88

./a.out > tmp.txt  //将标准输出定位到tmp.txt中,这时为全缓冲

cat tmp.txt

a write to stdout

before fork

pid = 432, glob = 7, var = 89

before fork

pid = 431, glob = 6, var = 88

  这里之所以会出现两次before fork是因为标准I/O 当输出定位到终端设备的时候是行缓冲,因此在fork之前,该缓冲碰到了换行符,已经进行了冲洗,所以不会再被子进程所拷贝,但是当输出定位到文件的时候,会变为全缓冲而被子进程拷贝。

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int glob = 6;

int main()
{
    int var;
    pid_t pid;

    var = 88;
    printf("before fork\n");

    if((pid = vfork()) < 0)
    {
        printf("vfork error\n");
        exit(-1);
    }
    else if(pid == 0)
    {
        //child
        glob++;
        var++;
        _exit(0);
    }
    /*
     * 父进程可以执行到这里
     * /
    printf("pid = %d, glob = %d, bar = %d\n", getpid(), glob, var);
    exit(0);
}

运行结果如下:

before fork

pid = 29039, glob = 7, var = 89

  从上面可以看到,子进程中对于变量的修改在父进程中是可见的。

3.父子进程的文件共享

  每一个进程都有一个文件表项,表示打开的文件及状态

  

  创建子进程之后,子进程会复制父进程的所有的打开文件描述符,这样的话就会出现父子进程使用了同一个文件偏移量,

  

  因此父子进程在处理文件的时候就要注意顺序的保持。

进程结束

exit函数

  进程有以下5中正常种植方式

  • main函数中调用执行return语句,等效于调用exit
  • 调用exit其操作包括调用终止处理程序,关闭所有标准I/O流
  • 调用_exit()_Exit()并不清洗I/O流
  • 进程中的最后一个线程在其启动例程中执行返回语句
  • 进程中最后一个线程执行pthread_exit 函数

      除此之外,进程还有异常退出的情况。

      对于任何一种退出情况,我们都希望父进程能知道子进程是如何结束的,对于三个终止函数(exit、 _exit和_Exit),它们将退出状态 作为参数返回给父进程,而异常退出的情况,内核产生终止状态

父进程获得子进程的终止状态

  父进程利用wait或者waitpid 来获得子进程的终止状态或者退出状态

  

  父进程调用这两个函数可能会出现下面的情况:

  • 如果其所有子进程都还在运行,则父进程阻塞,等待一个子进程终止
  • 如果一个子进程已经终止,正等待父进程获取其终止状态,则取得子进程的终止状态并立即返回
  • 如果没有任何子进程,则返回出错。
pid_t wait(int *status)
pid_t waitpid(pid_t pid, int *status, int options)
//成功则返回进程ID,失败返回-1

  这两个函数有所区别:

  • 在一个子进程终止之前,wait将其调用者阻塞,而waitpid有一个选项可使调用者不阻塞
  • waitpid并不等待在其调用之后的第一个终止进程,它有pid参数,用来指定等待某个进程结束。

      下面的程序用来演示不同的exit值

#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
    pid_t pid;
    int status;

    if((pid = fork()) < 0)
    {
        printf("fork error");
        exit(-1);
    }
    else if(pid == 0)          /* child */
        exit(7);

    if(wait(&status) != pid)    /* wait for child */
    {
        printf("wait error");
        exit(-1);
    }
    printf("%d", status);

    if((pid = fork()) < 0)
    {
        printf("fork error");
        exit(-1);
    }
    else if(pid == 0)          /* child */
        abort();        /* generate SIGABRT */

    if(wait(&status) != pid)    /* wait for child */
    {
        printf("wait error");
        exit(-1);
    }
    printf("%d", status);

  if((pid = fork()) < 0)
    {
        printf("fork error");
        exit(-1);
    }
    else if(pid == 0)          /* child */
        status /= 0;  /* divide by 0 generate SIGFPE */

    if(wait(&status) != pid)    /* wait for child */
    {
        printf("wait error");
        exit(-1);
    }
    printf("%d", status);

  exit(0);
}

僵尸进程和孤儿进程

僵尸进程和孤儿进程的概念

  我们知道在unix/linux中,正常情况下,子进程是通过父进程创建的,子进程在创建新的进程。子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程 到底什么时候结束。 当一个 进程完成它的工作终止之后,它的父进程需要调用wait()或者waitpid()系统调用取得子进程的终止状态。

  孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

  僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。

僵尸进程和孤儿进程的危害

  unix提供了一种机制可以保证只要父进程想知道子进程结束时的状态信息, 就可以得到。这种机制就是: 在每个进程退出的时候,内核释放该进程所有的资源,包括打开的文件,占用的内存等。 但是仍然为其保留一定的信息(包括进程号the process ID,退出状态the termination status of the process,运行时间the amount of CPU time taken by the process等)。直到父进程通过wait / waitpid来取时才释放。 但这样就导致了问题,如果进程不调用wait / waitpid的话, 那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程. 此即为僵尸进程的危害,应当避免。

  孤儿进程是没有父进程的进程,孤儿进程这个重任就落到了init进程身上,init进程就好像是一个民政局,专门负责处理孤儿进程的善后工作。每当出现一个孤儿进程的时候,内核就把孤 儿进程的父进程设置为init,而init进程会循环地wait()它的已经退出的子进程。这样,当一个孤儿进程凄凉地结束了其生命周期的时候,init进程就会代表党和政府出面处理它的一切善后工作。因此孤儿进程并不会有什么危害。

  任何一个子进程(init除外)在exit()之后,并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构,等待父进程处理。这是每个子进程在结束时都要经过的阶段。如果子进程在exit()之后,父进程没有来得及处理,这时用ps命令就能看到子进程的状态是“Z”。如果父进程能及时 处理,可能用ps命令就来不及看到子进程的僵尸状态,但这并不等于子进程不经过僵尸状态。 如果父进程在子进程结束之前退出,则子进程将由init接管。init将会以父进程的身份对僵尸状态的子进程进行处理。

  僵尸进程危害场景:

  例如有个进程,它定期的产 生一个子进程,这个子进程需要做的事情很少,做完它该做的事情之后就退出了,因此这个子进程的生命周期很短,但是,父进程只管生成新的子进程,至于子进程 退出之后的事情,则一概不闻不问,这样,系统运行上一段时间之后,系统中就会存在很多的僵死进程,倘若用ps命令查看的话,就会看到很多状态为Z的进程。 严格地来说,僵死进程并不是问题的根源,罪魁祸首是产生出大量僵死进程的那个父进程。因此,当我们寻求如何消灭系统中大量的僵死进程时,答案就是把产生大 量僵死进程的那个元凶枪毙掉(也就是通过kill发送SIGTERM或者SIGKILL信号啦)。枪毙了元凶进程之后,它产生的僵死进程就变成了孤儿进 程,这些孤儿进程会被init进程接管,init进程会wait()这些孤儿进程,释放它们占用的系统进程表中的资源,这样,这些已经僵死的孤儿进程 就能瞑目而去了。

僵尸进程的避免

  

 通过fork两次来避免僵尸进程的产生

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>

int main()
{
    pid_t  pid;
    //创建第一个子进程
    pid = fork();
    if (pid < 0)
    {
        perror("fork error:");
        exit(1);
    }
    //第一个子进程
    else if (pid == 0)
    {
        //子进程再创建子进程
        printf("I am the first child process.pid:%d\tppid:%d\n",getpid(),getppid());
        pid = fork();
        if (pid < 0)
        {
            perror("fork error:");
            exit(1);
        }
        //第一个子进程退出
        else if (pid >0)
        {
            printf("first procee is exited.\n");
            exit(0);
        }
        //第二个子进程
        //睡眠3s保证第一个子进程退出,这样第二个子进程的父亲就是init进程里
        sleep(3);
        printf("I am the second child process.pid: %d\tppid:%d\n",getpid(),getppid());
        exit(0);
    }
    //父进程处理第一个子进程退出
    if (waitpid(pid, NULL, 0) != pid)
    {
        perror("waitepid error:");
        exit(1);
    }
    exit(0);
    return 0;
}

子进程执行程序

  fork函数执行之后,子进程往往需要调用一种exec函数执行另外的程序。

  其中execve()是内核实现的函数,其他函数都是通过调用这个函数实现的

int execl(const char *pathname, const char *arg0, ... /* (char *)0 */); (char *)0 为可选参数

int execv(const char *pathname, char *const argv[]);

int execle(const char *pathname, const char *arg0, ... /* (char *)0 , char *const envp[] */);   (char *)0和char *const envp[]为可选参数

int execve(const char *pathname, char *const argv[], char *const envp[]);

int execlp(const char *filename, const char *arg0, ... /* (char *)0 */);

int execvp(const char *filename, char *const argv[]);

  filename中包含 / 的话就是路径名,不然在就PATH环境变量中查找函数中所指定的文件。

#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>

char *env_init[] = {"USER=unknown", "PATH=/tmp", NULL};

int main()
{
    pid_t pid;
    if((pid = fork()) < 0)
    {
        printf("fork error");
        exit(-1);
    }
    else if(pid == 0)
    {
        if(execle("/home/sar/bin/echoall", "echoall", "myarg1", "myarg2", (char *)0, env_init) < 0)
        {
            printf("execle error");
            exit(-1);
        }
    }

    if(waitpid(pid, NULL, 0) < 0)
    {
        printf("waitpid error");
        exit(-1);
    }

    if((pid = fork()) < 0)
    {
        printf("fork error");
        exit(-1);
    }
    else if(pid == 0)
    {
        if(execlp("echoall", "echoall", "only 1 arg", (char *)0) < 0)
        {
            printf("execlp error");
            exit(-1);
        }
    }
    exit(0);
}

Linux内核中的进程管理

进程描述符——task_struct

  内核将进程的列表放在任务队列(双向循环列表)中,列表中元素类型为task_struct(进程描述符),下面是其中的片段

  

struct task_struct {

    volatile long state;
    void *stack;
    unsigned int flags;

    int prio, static_prio;

    struct list_head tasks;

    struct mm_struct *mm, *active_mm;

    pid_t pid;
    pid_t tgid;

    struct task_struct *real_parent;

    char comm[TASK_COMM_LEN];

    struct files_struct *files;

    ...

};

  在结构体中可以看到几个预料之中的项,比如执行的状态、堆栈、一组标志、父进程、执行的线程(可以有很多)以及开放文件。

  state 变量是一些表明任务状态的比特位。最常见的状态有:TASK_RUNNING 表示进程正在运行,或是排在运行队列中正要运行;TASK_INTERRUPTIBLE 表示进程正在休眠、TASK_UNINTERRUPTIBLE 表示进程正在休眠但不能叫醒;TASK_STOPPED 表示进程停止等等。

  flags 定义了很多指示符,表明进程是否正在被创建(PF_STARTING)或退出(PF_EXITING),或是进程当前是否在分配内存(PF_MEMALLOC)。

  每个进程都会被赋予优先级(static_prio),但进程的实际优先级是基于加载以及其他几个因素动态决定的。优先级值越低,实际的优先级越高。

  tasks 字段提供了链接列表的能力。它包含一个 prev 指针(指向前一个任务)和一个 next 指针(指向下一个任务)。

  进程的地址空间由 mmactive_mm 字段表示。mm 代表的是进程的内存描述符,而 active_mm 则是前一个进程的内存描述符(为改进上下文切换时间的一种优化)。

  

  在Linux2.6版本之前,各个进程的task_struct 放在它们内核栈的尾端,这样的好处是可以直接利用栈指针就可以访问task_struct 而避免了利用寄存器存储task_struct 地址。2.6版本以后,在栈底(向下增长的栈)或栈顶(向上增长的栈)(不论怎么样,还是在内核栈的尾端)创建新的结构体thread_info。而通过栈指针访问thread_info,再通过task_struct 在其中的偏移找到task_struct

  

Linux进程创建

  Linux以及其他Unix系统的进程创建很特别。其他很多操作系统都提供了产生进程的机制,首先在新的地址空间创建进程,读入可执行文件,最后开始执行。但是Unix系统将这些步骤分开为fork()exec()两部分。

写时拷贝(copy-on-write)

  正如前面所说,现在内核在fork之后不会完全将父进程的资源赋值给子进程,而是采用写时拷贝的技术,也就是说fork之后父子进程还是先是以只读方式共享父进程的地址空间,只有当子进程试图去修改的时候才会拷贝相应的资源,这样fork的实际开销就是复制父进程的页表以及给子进程创建唯一的进程描述符。

fork的过程

  Linux系统通过clone() 系统调用实现fork()这个调用可以通过参数来指明父子进程需要共享的资源,这个特征也是后面Linux实现线程的基础。fork()vfork()__clone() 都是通过各自需要共享所代表的参数调用clone(),然后由clone() 去调用do_fork()

  do_fork() 完成创建的大部分工作,该函数又调用copy_process(),然后让程序开始执行。调用的层次结构如下。

    

  copy_process()函数主要按下面的步骤进行:

  1)调用dup_task_struct() 为新进程分配内核栈、thread_info结构以及task_struct,这些值与当前进程的值相同。此时子进程与父进程的描述符是完全相同的。

  2)检查并确保新进程创建这个子进程之后,当前用户所用的进程数目没有超出它所分配的资源的限制。

  3)子进程开始着手将自己和父进程区分开来,进程描述符内的很多成员都要被清0,或设为初始值,但是还是有很多成员没有修改。

  4)子进程的状态state被修改为TASK_UNINTERRUPTIBLE(即使有信息唤醒该进程,也不会响应),以保证它不会投入运行。

  5)copy_process()调用copy_flags()以更新task_structflags成员。表明是否有超级用户权限的PF_SUPERPRIV被清0,表明进程还没有被exec()函数调用的PF_FORKNOEXEC标志位被设置。

  6)调用alloc_pid()为新进程分配一个有效地pid

  7)根据clone()传进来的参数,copy_process()拷贝或共享打开的文件、文件系统信息、信号处理函数、进程地址空间等。

  8)最后copy_process()收尾并返货一个指向子进程的指针。

Linux进程结束

进程退出

  进程结束的时候,内核必须释放它所占用的资源,并将这个消息告知父进程。一般进程的析构是自身引起的。调用exit()后,大部分的工作由do_exit()处理。

  1)将task_struct中的flags设为PF_EXITING

  2)调用del_timer_sync()删除任一内核计数器。根据返回的结果,确保没有定时器在排队,也没有定时器处理程序在运行。

  3)如果BSD的记账功能开启,调用acct_update_intrgrals()来输出记账信息。

  4)调用exit_mm()函数释放进程占用的mm_struct(进程用户空间结构),如果没有别的进程共享,则彻底释放。

  5)调用sem_exit()函数。如果进程排队等候IPC信号,则里考队列。

  6)调用exit_files()exit_fs()以分别递减文件描述符和文件系统数据的引用计数。如果引用计数为0,证明没有进程使用,则彻底释放。

  7)将存放在task_structexit_code成员中的任务退出码设置为由exit()提供的退出代码,或者去完成任何其他由内核提供的退出动作。退出代码放在这里由父进程进行检索

  8)调用exit_notify()向父进程发送信号,给子进程重新找养父,养父为线程组中的其他线程或者为init进程,并将exit_state设置为EXIT_ZOMBIE

  9)do_exit()调用schedule()切换到新进程,因为处于EXIT_ZOMBIE的进程不会被调度,因此do_exit()不返回。

  至此,进程的资源都被释放了,剩下的就剩内核栈,thread_infotast_struct结构,要告知父进程来处理这些结构,不然就成僵尸进程了。

父进程回收退出进程的剩余结构

  上面说了,调用了do_exit()之后,尽管进程已经僵死不能再运行了,但是系统还保留了它的进程描述符。需要报告父进程让父进程来回收。wait()一族的函数都使调用wait4()系统调用来实现的。它的准动作是挂起调用它的进程,知道其中一个子进程退出,此时函数会返回该子进程的PID。此外,调用该函数时提供的指针会包含子进程退出时的退出码。

  释放进程描述符的时候,release_task()被调用:

  1)从pidhash上删除该进程,同时从任务列表中删除该进程。

  2)释放目前僵尸进程所使用的所有资源,并进行最后的统计和记录。

  3)如果这个进程是进程组的最后一个进程,并且领头进程已经四地哦啊,则通知僵死的零头进程的父进程。

  4)释放进程内核栈和thread_info结构所占的页,并释放task_struct所占的slab高速缓存。

参考

1.《UNIX环境高级编程》

2.《Linux内核设计与实现》

时间: 2024-10-12 12:50:07

Unix下的进程管理的相关文章

【笔记整理】unix/linux的进程管理(一)

Unix/Linux 下的进程管理 1. 进程与程序 ~~~~~~~~~~~~~ 1) 进程就是运行中的程序.一个运行着的程序, 可能有多个进程.进程在操作系统中执行特定的任务. 2) 程序是存储在磁盘上, 包含可执行机器指令和数据的静态实体. 进程或者任务是处于活动状态的计算机程序. 2. 进程的分类 ~~~~~~~~~~~~~ 1) 进程一般分为交互进程.批处理进程和守护进程三类. 2) 守护进程总是活跃的,一般是后台运行. 守护进程一般是由系统在开机时通过脚本自动激活启动, 或者由超级用户

linux下的进程管理(进程的基本了解及查看pstree,ps,pgrep命令)

Linux下的进程管理 1.什么是进程?程序是静态的文件进程是运行中的程序的一个副本进程存在生命周期(准备期,运行期,终止期)2.进程状态 状态 定义 R(TASK_RUNNING) . 可执行状态(RUNNING,READY)running:正在被处理 ready: 在排队, cpu处理进程个数有限 S(TASK_INTERRUPTIBLE) 可唤醒状态 :在cpu上使用的时间超时,此时被打入休眠状态,随着程序的调用会被唤醒 D(TASK_UNINTERRUPTIBLE) 不可唤醒状态 T(T

【归纳总结】Unix/linux下的进程管理(二):创建进程的函数及其应用、对比

创建进程的函数fork().vfork()和execl() 本次内容主要介绍Unix/linux下2个创建进程的函数fork和vfork以及它们的差别. 1.fork函数 (1)函数的格式 #include <unistd.h> pid_t fork(void); 函数功能: 主要用于以复制正在运行进程的方式来创建新的进程,其中新进程叫做子进程,正在运行的进程叫做父进程. 返回值: 函数调用成功时,父进程返回子进程的PID,子进程返回0,函数调用出错时,父进程返回-1,子进程没有被创建. 注意

Linux下的进程管理

在操作系统系统中,进程是一个非常重要的概念. 一.Linux中进程的相关知识 1.什么是进程呢? 通俗的来说进程是运行起来的程序.唯一标示进程的是进程描述符(PID),在linux内核中是通过task_struck和task_list来定义和管理进程的. 2.进程的分类 1)根据在linux不同模式下运行分为: 核心态:这类进程运行在内核模式下,执行一些内核指令(Ring 0). 用户态:这类进程工作在用户模式下,执行用户指令(Ring 3). 如果用户态的进程要执行一些核心态的指令,此时就会产

Unix 下 使用 RVM 管理 Ruby 和 gem

转载:http://www.ibm.com/developerworks/cn/aix/library/au-aix-manage-ruby/ ? 尽管 Internet Relay Chat.论坛和版本控制工具(如 Git 和 Github)令分布式开发变得十分简单,但是重建另一个开发人员的环境将会十分困难.在一个新的开发机器上支持现有代码体,需要至少匹配初始编码人员的部分(也有可能是全部)堆栈,或是匹配增强应用程序所必需的软件组件.堆栈可能要求使用某种操作系统(比如 UNIX?.Linux?

【归纳整理】Liunx下的进程管理(三),多进程的等待和终止

进程的正常退出 ------------------ 1. 从main函数中return. int main (...) { ... return x; } 等价于: int main (...) { ... exit (x); } 2. 调用标准C语言的exit函数. #include <stdlib.h> void exit (int status); 1) 调用进程退出, 其父进程调用wait/waitpid函数返回status的低8位. 2) 进程退出之前, 先调用所有事先通过atex

基于LINUX下的进程管理问题

什么是进程? 程序(program)放置在存储媒体中(如硬盘,光盘,软盘,磁带等)为实体文件的形态存在 进程:程序被触发后,执行者的权限与属性,程序的程序码与所需数据等都会被载入内存中,操作系统并给予这个内存内的单元一个识别码(PID),可以说,进程就是一个正在运行的程序 进程的状态: R(Running):该程序正在运行中: S(Sleep):该程序目前正在睡眠状态(idle),但可以被唤醒(signal) D:不可被唤醒的睡眠状态,通常进程可能在等待I/O的情况. T:停止状态(stop),

RHCE 学习笔记(7) 进程管理

这一节和前面比起来简单多了,主要是熟悉RHEL下的进程管理相关的常用命令 ps aux, pstree,top, jobs, kill, bg, fg 进程可以由一个进程的基础上运行另外一个进程,前者叫做父进程,后者是子进程. 比如我打开一个终端,这是一个进程,然后我在上面执行命令,打开新的程序,新的程序则是子进程. 比如说,我打开firefox 这个时候可以通过pstree来查看进程树 搜索一下firefox,可以看见 firefox是termianl的子进程 除了pstree,我们还经常使用

Linux 程序设计学习笔记----进程管理与程序开发(下)

转载请注明出处:http://blog.csdn.net/suool/article/details/38419983,谢谢! 进程管理及其控制 创建进程 fork()函数 函数说明具体参见:http://pubs.opengroup.org/onlinepubs/009695399/functions/fork.html 返回值:Upon successful completion, fork() shall return 0 to the child process and shall re