unix进程三个部分_unix进程控制块由哪四部分组成 - CSDN
  • UNIX系统中进程由以下三部分组成:①进程控制块PCB;②数据段;③正文段。  UNIX系统为了节省进程控制块所占的内存空间,把每个进程控制块分成两部分。一部分常驻内存,不管进程是否正占有处理器运行,系统经常...
    在UNIX系统中进程由以下三部分组成:①进程控制块PCB;②数据段;③正文段。
            UNIX系统为了节省进程控制块所占的内存空间,把每个进程控制块分成两部分。一部分常驻内存,不管进程是否正占有处理器运行,系统经常会对这部分内容进行查询和处理,常驻部分内容包括:进程状态、优先数、过程特征、数据段始址、等待原因和队列指针等,这是进行处理器调度时必须使用的一些主要信息。另一部分非常驻内存,当进程不占有处理器时,系统不会对这部分内容进行查询和处理,因此这部分内容可以存放在磁盘的对换区中,它随用户的程序和数据部分换进或换出内存。
            UNIX系统把进程的数据段又划分成三部分:用户栈区(供用户程序使用的信息区);用户数据区(包括用户工作数据和非可重入的程序段);系统数据区(包括系统变量和对换信息)。
            正文段是可重入的程序,能被若干进程共享。为了管理可共享的正文段,UNIX设置了一张正文表,每个正文段都占用一个表目,用来指出该正文段在内存和磁盘上的位置、段的大小以及调用该段的进程数等情况。
    展开全文
  • 这一周为了准备OS课程的Seminar而去研究了一下Unix进程调度,从网上的资料和我查阅的纸质资料上看,研究System V的比较多,所以我就拿System V来做例子。需要注意的一点是,System V第一版本是1983年发布的,...

    这一周为了准备OS课程的Seminar而去研究了一下Unix的进程调度,从网上的资料和我查阅的纸质资料上看,研究System V的比较多,所以我就拿System V来做例子。

    需要注意的一点是,System V第一个版本是1983年发布的,Sytem V Release 4(1988)最成功的一个版本,离现在也有点久远了,*nix各种分支进化到现在和80年代比应该发生了比较大的变化,但是它们的设计思想还是值得研究一番的。

    Unix启动过程

    Alt text

    • 引导程序自举
    • 引导程序完成后,系统控制权转移给Unix内核,Unix OS正式开始工作
    • 内核创建0号进程
    • 0号进程创建1号进程init,并将控制权交给init
    • init查询当前存在的终端数,为每一个终端创建一个新的管理进程
    • 管理进程等待用户登录
    • 用户登录后,系统为每一个用户启动一个shell进程
    • 用户输入命令,由shell进程创建新的进程

    Unix进程上下文结构

    • proc结构:常驻内存,记录了进程的基本信息。
    • user结构:不常驻内存,在进程执行时调入内存,记录了内存的私有信息和数据。
    • 正文段:程序代码和常量,可被多个进程访问的共享区域。
    • 数据段:进程的私有信息,用户态进程访问的区域。
    • 系统栈:进程在系统态执行时完成子程序嵌套和中断处理时使用的信息保留区,只能被系统态进程使用。
    • 用户栈:进程在用户态执行时完成子程序嵌套和中断处理时使用的信息保留区。

    0号进程三大任务

    • 由核心程序创建,在初始化时完成1号进程的创立
    • 在以后的管理中,负责进程的调度与分配
    • 在以后的管理中,负责进程的内外存交换

    Unix进程状态转换图

    Alt text

    用户态和系统态的切换

    Alt text
    PSW:处理器状态寄存器:反映了当前执行进程的访问方式,比如进程在何种状态下执行、中断的优先级的状态是怎样的、进入中断或陷入指令之前处理器的执行方式是怎样的等等。

    进程调度程序(0号进程的switch程序)

    • 对参与竞争CPU且已具备执行条件的进程进行分析和裁决
    • 对选中的进程做处理器控制权移交
    • 管理进程运行中各种状态的转换
    • 完成进程在系统内外存之间的交换

    调度算法

    动态优先级多级反馈循环调度法(Round Robin With Multilevel Feedback)

    1. 当一个时间片结束时,系统为所有进程计算优先级
    2. 计算后查看是否有优先级高于当前进程且处于“内存就绪”的进程,将它们选出
    3. 将选出的进程设置调度标志
    4. 下一轮调度开始时,调度已设置了高优先级调度标志且优先级最高的进程,让其在处理器中开始运行

    优先数计算

    Unix是根据优先数来判断进程调度优先级的。
    优先数是进程的proc结构中的char p_pri字段,值的范围是0-127,优先数越小,优先级越高。
    0-49之间的优先数是系统态进程的优先级,用户态下的进程优先级为50-127之间。

    计算公式

    p_pri = p_cpu / 2 + PUSER + p_nice + NZERO

    • PUSER和NZERO是基本用户优先数的阈值,是系统预设的,分别是25和20
    • p_cpu表示该进程最近一次占用CPU的时间,对于当前进程,每个时钟中断(注意不是每个时间片)该值加1(最大值80)。若时钟中断周期是16.6ms,则一秒内右60个时钟中断
    • 新创建进程的p_cpu为0
    • p_nice是用户可以通过系统调用设置的一个优先级偏移值,默认为20。超级用户可以设置其在0到39之间,而普通用户只能增大该值

    一个时间片结束后,系统将每个进程的p_cpu除以2,这个过程称为衰减。
    衰减过后,系统重新计算每个进程的p_pri

    分析一下这条公式,系统运行时PUSER和NZERO是常数,而p_nice一般也是一个常数,所以进程优先数就取决于p_cpu。对于那些占用CPU较长时间的进程,其优先数在衰减后还是比那些最近占用CPU较短的进程大,所以其优先级会变小,反过来,那些不怎么占用CPU的进程的优先级会增加,所以会在下一次调度中被执行。这是一种负反馈调节。

    优先数0-49是内核保留的优先数,当进程睡眠(阻塞)时,就会被赋予一个系统优先级(0-49),由于比用户优先数小,所以这些进程醒来的时候(比如IO完成)能被及时处理。

    调度时机的疑问

    关于调度时机,是让我比较疑惑的一点,我手上的中文教材和网上的一个课件说的都是调度时机有以下两个:

    • 第一种情况:当进程执行中自动放弃处理机时(比如等待I/O,或者运行结束),进行一次进程调度
    • 第二种情况:当进程由系统态转入用户态时,系统安排一次调度,这样做的意图是使那些被设置了高优先级调度标志,并且在内存中就绪的进程可以有机会抢先进入执行状态

    然而在查到的外文资料里没有提到“调度时机”。

    如果是以上两个调度时机,那么说明在时间片结束的时候可能没有调度发生,因为只是发生了优先数计算,那么假设有一个用户态进程在执行过程中进行了大量计算(或者死循环),既没有主动放弃处理机,也没有从系统态到用户态的转换,那么处理机就一直被它占用。

    0号进程一直是系统态,如果0号进程在时间片结束、计算完优先数并设置标记以后,让之前的用户进程继续执行,是否算是一种“系统态到用户态的转换”?如果是,那么就出现了调度时机,这种时机的安排就是有效的。

    虽然有这个疑问,不过调度的主要思想我已经理解,也许后面的学习中这些疑问都会被解决。

    参考资料

    原文链接:http://blog.dyzeng.org/2016/03/17/Unix-scheduling/

    展开全文
  • UNIX进程   进程标识符 要想对进程控制,必须得获取进程的标识。每进程都有一非负整数表示的唯一进程ID,虽然是唯一的,但是进程ID可以重用。当一进程终止后,其进程ID就可以再次使用了。 系统中有...

    UNIX进程

     

    进程标识符


    要想对进程控制,必须得获取进程的标识。每个进程都有一个非负整数表示的唯一进程ID,虽然是唯一的,但是进程ID可以重用。当一个进程终止后,其进程ID就可以再次使用了。

    系统中有一些专用的进程。

    ID为0的进程通常是调度进程(常常被称为交换进程swapper)。该进程是内核的一部分,它不执行任何磁盘上的程序。

    进程ID1通常是init进程。此进程负责在自举内核后启动一个UNIX系统。init通常读与系统有关的初始化文件,并将系统引导到一个状态。init进程绝不会终止,它是一个普通的用户进程,但是它以超级用户特权运行。

    #include <unistd.h>

    pid_t  getpid(void) ;         //获取调用进程的进程ID

    pid_t  getppid(void) ;       //获取调用进程的父进程ID

    uid_t  getuid(void) ;         //获取调用进程的实际用户ID

    gid_t  getgid(void) ;         //获取调用进程的实际组ID

     

    进程创建


    #include <unistd.h>

    pid_t fork(void) ;

    一个现有进程可以调用fork函数创建一个新进程。由fork创建的新进程被称为子进程。

     

    新创建的子进程几乎但不完全与父进程相同。

    子进程得到与父进程用户级虚拟地址空间相同的(但是独立的)一份拷贝,包括文本、数据和bss段、堆以及用户栈。子进程还获得与父进程任何打开文件描述符相同的拷贝,这就意味着当父进程调用fork时,子进程可以读写父进程中打开的任何文件。

    父进程和新创建的子进程之间最大的区别在于它们有不同的PID

     

    fork函数被调用一次,但返回两次。两次返回的唯一区别是子进程的返回值是0,而父进程的返回值则是新子进程的进程ID

    例:

    #include<unistd.h>
    #include<stdio.h>
    #include<errno.h>
    #include<stdlib.h>
     
    int main()
    {
       pid_t pid ;
       int   x = 1 ;
     
       pid = fork() ;
       if (pid == 0) /*Child*/
       {
           printf("child : x=%d\n", ++x) ;
           exit(0) ;
       }
     
       /*Parent*/
       printf("parent :x=%d\n", --x) ;
       exit(0) ;
    }
     
    //执行结果:
    //parent: x=0
    //child: x=2

    注意:

    并发执行。父进程和子进程是并发运行的独立进程。内核能以任何方式交替执行它们的逻辑控制流中的指令。(故此程序的执行结果在不同的系统上可能相反)

    相同的但是独立的地址空间。因为父进程和子进程是独立的进程,它们都有自己的私有地址空间。父进程和子进程对x所做的任何改变都是独立的,不会反映在另一个进程的存储器中。

    共享文件。当运行这个示例程序时,我们注意到父进程和子进程都把它们的输出显示在屏幕上。原因是子进程继承了父进程所有的打开文件。当父进程调用fork时,stdout文件是被打开的,并指向屏幕。子进程继承了这个文件,因此它的输出也是指向屏幕的。

     

    由于在fork之后经常跟随着exec,所以现在的很多实现并不执行一个父进程数据段、栈和堆的完全复制。而是使用了写时复制(Copy-On-Write, COW)技术。这些区域由父、子进程共享,而且内核将它们的访问权限改变为只读的。如果父、子进程中的任一个试图修改这些区域,则内核只为修改区域的那块内存制作一个副本,通常是虚拟存储器系统中的一

     

    fork有下面两种用法:

    1、一个父进程希望复制自己,使父子进程同时执行不同的代码段。(开始时只有一个进程,后来fork出了两个)

    2、一个进程要执行一个不同的程序。在这种情况下,子进程从fork返回后立即调用exec(创建了一个全新进程)子进程在forkexec之间可以更改自己的属性。例如I/O重定向,用户ID、信号安排等。

     

    //fork函数示例
    //fork就是分支的起点
    //之前是一个进程,遇到fork之后便一分为二,成两个进程。
    #include<unistd.h>
    #include<stdio.h>
    #include<errno.h>
    #include<stdlib.h>
     
    int glob = 6 ;
    char buf[] = "awrite to stdout\n" ;
     
    int
    main(int argc, char**argv)
    {
       int   var ;
       pid_t pid ;
     
       var = 123;
       if (write(STDOUT_FILENO,buf, sizeof(buf)-1) != sizeof(buf)-1)
           perror("write error") ;
     
       printf("beforefork\n") ;
     
       if ((pid = fork()) < 0)
           perror("fork error") ;
       else if (pid == 0) //子进程
       {
           glob++ ;
           var++ ;
       }
       else //父进程
       {
           sleep(3) ; //挂起3秒,让子进程先运行
       }
     
       //父子进程都有的相同的程序正文
       printf("pid = %d, glob= %d, var = %d\n", getpid(), glob, var) ;
       exit(0);
    }

    【在fork进程时,注意标准I/O的缓冲问题】

    write函数不带缓冲的,但标准I/O库是带缓冲的。如果标准输出连到终端设备,则它是行缓冲的(由换行符冲洗),否则它是全缓冲的

     

    若把上面程序的输出重定向到文件:./a.out> test.txt 则"beforefork\n"会输出两次

    原因是当将标准输出重定向到一个文件时,标准I/O是全缓冲的。在fork之前调用了printf一次,但当调用fork时,该行数据仍在缓冲区中,然后将父进程数据空间复制到子进程中时,该缓冲区也被复制到子进程中。于是那时父、子进程各自有了带该行内容的标准I/O缓冲区。当每个进程终止时,最终会冲洗其缓冲区中的副本。

     

    文件共享

    在重定向父进程的标准输出时,子进程的标准输出也被重定向。fork的一个特性是父进程的所有打开文件描述符都被复制到子进程中。父、子进程的每个相同的打开描述符共享一个文件表项。(因为子进程获取了父进程文件指针的副本)

    这种共享文件的方式使父、子进程对同一文件使用了一个文件偏移量。如果父、子进程写到同一描述符文件,但又没有任何形式的同步,那么它们的输出就会相互混合。

     

    进程终止


    exit函数

    进程有下面五种正常终止方式:

    1、 执行return语句。(这等效于调用exit

    2、 调用exit函数。(其操作包括调用各终止处理程序,然后关闭所有标准I/O流等。)

    3、 调用_exit_Exit函数。(立即进入内核。此二者为进程提供一种无需运行终止处理程序或信号处理程序而终止的方法。)

    4、 进程的最后一个线程在其启动例程中返回。

    5、 进程的最后一个线程调用pthread_exit函数。

    三种异常终止方式:

    1、调用abort。(它产生SIGABRT信号)

    2、当进程接收到某些信号时。(比如终止信号)

    3、最后一个线程对取消请求作出响应。

     

    当一个进程由于某种原因终止时,内核并不是立即把它从系统中清除。相反,进程被保持在一种已终止的状态中,直到被它的父进程回收。当父进程回收已终止的子进程时,内核将子进程的退出状态传递给父进程,然后抛弃已终止的进程,从此时开始,该进程就不存在了,一个终止了但还未被回收的进程称为僵死进程。

     

    在任意一种情况下,该终止进程的父进程都能用waitwaitpid函数取得其终止状态。

     

      若父进程在子进程之前终止,则子进程的父进程都改变为init进程。我们称之为由init进程领养。(在一个进程终止时,内核逐个检查所有活动进程,看它是否还有活的子进程,如果有,则将它子进程的父进程ID更改为1,即init进程的ID
    init进程的PID1,并且是在系统初始化时由内核创建的、长时间运行的程序】

      若子进程在父进程之前终止,则当父进程调用waitwaitpid函数时,可以获得子进程的终止状态信息。(内核为每个终止子进程保存了一定量的信息)

     

    僵死进程一个已经终止,但是其父进程尚未对其进行善后处理(获取终止子进程的终止状态信息,释放它占用的资源)的进程被称为僵死进程(zombie)。[即:已死,但无人收尸]

    init领养的进程不会变成僵死进程。因为init被编写成无论何时只要有一个子进程终止,init就会调用一个wait函数取得其终止状态。这也就防止了系统中有很多僵死进程。

    (这只能做到父进程先死,子进程不会变僵死进程。若子进程先死,则防止僵死进程的责任就交给我们了。---内核在父进程终止时只检查其活着的子进程。)

     

    waitwaitpid函数

    【当一个进程正常或异常终止时,内核就向其父进程发送SIGCHLD信号。】

    对于这种信号,系统的默认动作是忽略,当然,我们也可以设置为捕捉,并提供一个信号处理函数。

     

    #include <sys/wait.h>

    pid_t wait(int *statloc) ;           // statloc为返回的终止状态存放处

    pid_t waitpid(pid_t pid, int *statloc, int options) ;

    父进程调用这两个函数,只要一有子进程终止,则此函数就取得该子进程的终止状态立即返回。否则一直阻塞。(若它没有任何子进程,则立即出错返回)

     

    这两个函数的区别:

      在一个子进程终止前,wait使其调用者阻塞,而waitpid则有一个选项,可使调用者不阻塞。(options设置为WNOHANG

      wait只获取在其调用之后的第一个终止子进程,而waitpid则有参数,可控制它所等待的进程。(pid设置为不同的值,有不同的含义。)

     

    防止僵死进程

    若在父进程中调用waitpid函数,则它只能获取第一个终止的子进程状态,其他子进程可能变为僵死进程。若在调用waitpid之前就有子进程结束,则更糟。

    若在SIGCHLD的信号处理函数中调用waitpid,则效果好一些,但也可能会产生僵死进程。因为若在信号处理函数执行期间,又有多个子进程结束,发出SIGCHLD信号,UNIX系统只投递一次信号。这样会有子进程的终止状态得不到获取。

    有效方式1:父进程调用sigaction函数绑定信号SIGCHLD的信号处理函数时,把其选项字段设置为SA_NOCLDWAIT,则可防止僵死子进程。(子进程终止后,内核自动把其终止状态信息丢弃)父进程可随时结束,不必等到所有子进程终止。  详情见UNIX信号博文

    有效方式2:调用fork两次以避免僵死进程。

    //调用fork两次,以避免僵死进程。
    #include<unistd.h>
    #include<stdio.h>
    #include<errno.h>
    #include<stdlib.h>
     
    int
    main(void)
    {
       pid_t pid ;
     
       if ((pid = fork()) < 0)
           perror("fork error") ;
       else if (pid == 0)  //子进程的作用就是创建孙进程,然后把它托付给init进程
       {
           if((pid = fork()) < 0)
               perror("fork error") ;
           elseif (pid == 0) //以下就是实际做事的 孙进程1代码段
           {
               sleep(2) ; //要让子进程先运行完 终止
               //打印出其父进程ID
               printf("grandchild 1, parent pid = %d\n", getppid()) ;
               exit(0) ;
           }
     
           if((pid = fork()) < 0)
               perror("fork error") ;
           elseif (pid == 0) //以下就是实际做事的 孙进程2代码段
           {
               sleep(2) ;
               //打印出其父进程ID
               printf("grandchild 2, parent pid = %d\n", getppid()) ;
               exit(0) ;
           }
     
           //终止自己,这样init就领养了各孙进程
           exit(0) ;
       }
       
       //以下是父进程代码段
       //父进程需要等待子进程(防止子进程变zombie)但这种等待时间极短(子进程很快便终止了)
       if (waitpid(pid, NULL, 0) !=pid)
           perror("waitpid error") ;
     
       exit(0) ;
    } 

    一般的父进程要写个循环轮询wait是否出错返回即轮询所有的子进程是否都已终止),这样父进程必须在所有子进程终止之后才能终止。

    而此法:

    父进程只需等待一个子进程结束(它会很快终止),而实际工作的进程由子进程fork,然后子进程终止这些孙进程就被init接管了,init可避免它们变为僵死进程。

    但需要注意的是:各孙进程在运行前要sleep一下,以便让子进程先终止。(若孙进程先终止,则变zombie)

     

    加载并运行程序


    exec函数族

    当进程调用一种exec函数时,该进程执行的程序完全替换为新程序。因为调用exec并不创建新进程,所以前后的进程ID并未改变。exec只是用一个全新的程序替换了当前进程的正文、数据、堆和栈段。

     

    #include <unistd.h>

    int execl (const char*pathname, const char* arg0,………/*(char*)0*/) ;

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

    函数execlexecv的区别与参数表的传递有关(l表示listv表示vector

    execl要求将新程序的每个命令行参数都说明为一个单独的参数,这种参数表以空格指针结尾。

    execv则先构造一个指向各参数的指针数组,然后将该数组地址作为这个函数的参数。

     

    [注意]

    system函数不同,exec函数族是用一个全新程序替换了当前进程的正文,故当前进程调用excl函数之后的语句不会被执行。

     

    #include <unistd.h>

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

    execve函数加载并运行可执行目标文件pathname,且带参数列表argv环境变量列表envp

    参数列表argv指向一个以null结尾的指针数组,其中每个指针都指向一个参数串。按照惯例,argv[0]是可执行目标文件的名字。

    环境变量列表envp指向一个以null结尾的指针数组,其中每个指针指向一个环境变量串,其中每个串都是形如”NAME=VALUE”的名字-值对。


     

    execve调用加载器加载pathname的程序,当加载器运行时,它创建Linux进程经典虚拟存储器映像(通过创建设置页表)。在可执行文件中段头部表的指导下,加载器将可执行文件的相关内容拷贝到代码和数据段(即填代码段和数据段对应的页表项)。接下来。加载器跳转到程序的入口点,也就是符号_start的地址。在_start地址处的启动代码startup code)是在目标文件中定义的,对所有C程序都一样。

    0x080480c0 <_start>

       call __libc_init_first

       call _init   //初始化例程

       call atexit

       call main

       call _exit  //在应用程序返回后,启动代码调用_exit程序,它将控制返回给操作系统

     

    main开始在一个32Linux进程中执行时,用户栈有如图所示的组织结构:


     

    Unix提供了几个函数来操作环境数组

    #include <stdlib.h>

    char* getenv(constchar *name) ;

    getenv函数在环境数组中搜索字符串”name=value”。如果找到了,它就返回一个指向value的指针,否则它就返回NULL

     

    设置和删除环境字符串的函数:

    #include <stdlib.h>

    int    setenv(const char* name, const char* newvalue, int overwrite) ;

    void unsetenv(constchar* name) ;

     

     

    system函数


    在程序中执行一个命令字符串很方便。

    ISO C定义了system函数,但其对操作系统的依赖很强。

    #include <stdlib.h>

    int  system(constchar * cmdstring) ;

    (其效果相当于在控制台输入命令,这样,可以让我们在程序中用到shell命令)

     

    system函数在实现中调用了forkexecwaitpid

    使用system而不是直接使用forkexec的优点是:system进行了所需的各种出错处理以及各种信号处理。(故:忘掉exec函数吧,虽然它有更强大的功能,但一般用system函数足矣。)

     

    我们可以利用system函数起一个与当前进程关联不大的进程(这个进程有独立的exe文件)

    execl函数不同,system函数起了一个子进程,故当前进程调用system函数之后的语句会被正常执行。

    [注意]

    如果一个进程正以特殊的权限(设置用户或设置组ID)运行,它又想生成另一个进程执行另一个程序,则它应当直接使用forkexec,而且在fork之后、exec之前要改回到普通权限。设置用户ID或设置组ID程序绝不应调用system函数

     

    进程时间


    时间值(UNIX系统一直使用两种不同的时间值)

      日历时间

    该值是自197011日以来国际标准时间(UTC)所经过的秒数累计值。这些时间值可以用于记录文件的最近一次的修改时间等。(其计时粒度较大,以秒为单位)

     

      进程时间

    也被称为CPU时间,用以度量进程使用的中央处理器资源。进程时间以时钟滴答计算。(取每秒钟为5060100个滴答。)可用sysconf函数得到每秒钟滴答数。

     

    UNIX使用三个进程时间值:

    墙上时钟时间:它是进程运行的时间总量,其值与系统中同时运行的进程数有关。(进程可能被切换,挂起)

    用户CPU时间:它是执行用户指令所用的时间。

    系统CPU时间:它是该进程中执行内核程序所经历的时间。例如readwrite

    用户CPU时间和系统CPU时间之和被称为CPU时间。(它们都是占用CPU的时间,不包括进程被挂起等待的时间。而墙上时钟时间进程生命期的所有时间)

     

    任一进程都可调用times函数以获得它自己及已终止子进程的上述值。

    #include <sys/times.h>

    clock_t times(struct tms * buf) ;

    //返回流逝的墙上时钟时间(单位:时钟滴答数)此值是相对于过去的某一时刻测量的,所以不能用其绝对值,要用两个时间点的差值。

    times函数还把用户CPU时间和系统CPU时间填在了buf指向的结构中。

    sysconf(_SC_CLK_TCK)返回每秒时钟滴答数。

     

    进程同步

    可用信号实现

    可用管道实现

     

    小结

    进程控制原语

    fork 可创建新进程。

    exec 可以执行新程序。

    exit 处理终止

    wait 等待终止。

     

    fork可以创建新进程,用exec可以执行新程序。exit函数和两个wait函数处理终止和等待终止。这些是我们需要的最基本的进程控制原语。

     

    附:操作进程的工具


    Linux系统提供了大量的监控和操作进程的有用工具:

    STRACE: 打印一个正在运行的程序和它的子进程调用的每个系统调用的轨迹。(用-static编译你的程序,能得到一个更干净的、不带有大量与共享库相关的输出的轨迹)

    PS:      列出当前系统中的进程(包括僵死进程)

    TOP:    打印出关于当前进程资源使用的信息。

    PMAP:   显示进程的存储器映射。

    /proc:          一个虚拟文件系统,以ASII文本格式输出大量内核数据结构的内容,用户程序可以读取这些内容。比如,输入”cat /proc/loadavg”,观察在Linux系统上当前的平均负载。

     

     

    展开全文
  • unix进程终止方式

    2012-08-07 21:41:37
    unix系统中,有8种方式可以使进程终止,其中五种为正常终止,种为异常终止。 五种正常终止方式为: 1.从mian返回 2.调用exit() 3.调用_exit()或_Exit() 4.最后一线程从启动例程返回 5.最后一现成调用...

    unix系统中,有8种方式可以使进程终止,其中五种为正常终止,三种为异常终止。

    五种正常终止方式为:

    1.从mian返回

    2.调用exit()

    3.调用_exit()或_Exit()

    4.最后一个线程从启动例程返回

    5.最后一个现成调用pthread_exit

    三种异常终止方式:

    6.调用abort()

    7.接到一个信号并终止

    8.最后一个线程对取消请求作出响应
    展开全文
  • 本文将《unix环境高级编程》一书中所涉及的几种重要的进程间通信方式(Inter-Process Communication)进行简单总结,总的来说,进程间通信有以下几种: (1).
  • 进程的组成部分

    2019-04-01 17:11:16
    UNIX系统中进程由以下三部分组成: 进程控制块PCB 数据段 正文段 进程控制块(PCB)是用来记录进程状态及其他相关信息的数据结构,PCB是进程存在的唯一标志,PCB存在则进程存在。系统创建进程时会产生一PCB...
  • unix ps查看进程

    2011-07-04 10:06:29
    要对进程进行监测和控制,首先必须要了解当前进程的情况,也就是需要查看当前进程,而ps命令就是最基本同时也是非常强大的进程查看命令.使用该命令可以 确定有哪些进程正在运行和运行的状态、进程是否结束、进程有没有...
  • UNIX的传统倾向于将一任务交给一个进程全权受理,但是一任务内部也不仅仅是一执行绪,比如一公司的所有成员,大家都在做同一件事,每人却只负责一部分,粒度减小之后,所有的事情便可以同时进行,不管怎样...
  • <br /> 摘要:本文以Linux ,Unix ,Windows 操作系统为例,分析其进程调度策略,以期对进程调度过程有更...这就要求进程调度程序按一定的策略,动态地把处理机分配给处于就绪队列中的某一个进程,以使之执
  • UNIX
  • 原文链接:http://blog.csdn.net/xyang81/article/details/51555473Supervisor(http://supervisord.org/)是用Python开发的一client/server服务,是Linux/Unix系统下的一个进程管理工具,不支持Windows系统。...
  • 后台进程 默认情况下,进程是在前台运行的,这时就把shell给占据了,...对于那些没有交互的进程,很多时候,我们希望将其在后台启动,可以在启动参数的时候加一'&'实现这目的。  tianfang > run &  
  • 探索运行在 UNIX 操作系统下的进程的生命周期 Sean A. Walberg (sean@ertw.com), 高级网络工程师 2007 年 7 月 16 日 研究进程的生命周期,以便您能将所看到的系统上发生的事情与内核中发生的事情联系起来。...
  • 前言:前些天实现了unix socket的通信,本想完完全全自己写一篇博客记录下来,但写的时候发现对于socket知识的理解还有所欠缺,故引用其他博客写的比较好的部分综合一下,这样让大家更容易理解。 一、Unix socket...
  • 1:进程结束方式 在Unix环境中,有8中方式可以结束一个进程,通常用的是以下五种方式: 1:从main函数返回 2:调用exit函数 3:调用_exit函数或者是_Exit函数 4:从最后一线程中...
  • UNIX网络编程---守护进程和inetd超级服务器 一、概述 守护进程是在后台运行且不于任何控制终端挂链的进程UNIX系统有很多守护进程在后台工作(有20到50的数量级),执行不同的任务 守护进程没有控制终端通常源于...
  • unix 守护进程

    2010-10-18 17:00:00
    unix 守护进程 守护进程(Daemon)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。守护进程是一种很有用的进程。Linux的大多数服务器就是用守护进程...
  • 下面我就主要按照进程中最重要的三个函数来进行讲解。让大家通过阅读这一篇文章彻底明白进程这点事。希望对大家有所帮助。 1进程环境  在学习进程之前,一定要了解一下unix进程环境。系统如何对进程终止,...
  • 对于UNIX环境编程,工作中经常会用到相关知识,作为学习UNIX环境编程的经典书籍–UNIX环境高级编程,是每个UNIX编程人员必看的经典书籍之一,为了将相关知识重新进行学习,以系统的整合所学知识,遂以博文形式作为...
  • 本文转载自: 进程间的通信方式:  1....  管道可用于具有亲缘关系... 信号是在软件层次上对中断机制的一种模拟,它是比较复杂的通信方式,用于通知进程有某事件发生,一个进程收到一信号与处理器收到一中断
1 2 3 4 5 ... 20
收藏数 190,500
精华内容 76,200
关键字:

unix进程三个部分