Linux进程管理 简介

何为进程,我想这个问题大家再熟悉不过了吧,无非就是“执行中的程序”!
概念性的东西本文暂时忽略或者略微一提,详细信息还需要阅读相应的blog或专业书籍。(博主收藏了计算机相关的大量国内外知名书籍,需要的可以留言,免费奉上)

1. 进程资源

进程的运行需要内存、CPU等资源,系统为进程提供两种资源:

内核空间进程资源:即PCB(Process Control Block, 进程控制块),包括PID、PPID、打开的文件表项、当前目录与当前终端信息等;

特点:只能通过系统调用才可以访问,当前进程退出,由另外的进程进行资源回收
详细定义:可见 /usr/src/kernels/xxx/include/linux/sched.hstruct task_struct

用户空间进程资源:包括进程的代码段、数据段、堆、栈以及可共享的库的内存空间

2. 进程状态信息

mark
进程的状态在Linux系统中主要分为五个:

  • Running: TASK_RUNNING
    运行态或就绪态(得了了除CPU意外的其它所有资源)
  • Waitting:

    • Waitting Interuptable:TASK_INTERRUPTIBLE
      等待状态,等待资源有效时唤醒,可被中断唤醒
    • Waitting Uninteruptable:TASK_UNINTERRUPTIBLE
      等待状态,等待资源有效时唤醒,不可被中断唤醒
  • Stop: TASK_STOPPED
    进程被暂停,当再次允许时可再次执行
  • Zombie:TASK_ZOMBIE
    进程用户资源空间被释放,但PCB并未释放,等待父进程回收

3. 进程属性

1). PID

进程号(Process IDentification),是进程的唯一标识,为一个正整数,由内核分配,用户无法修改。

获取PID的函数为:

  • 函数:getpid()
  • 作用
    获取该进程的PID
  • 头文件

        #include <unistd.h>
  • 函数原型

        pid_t getpid(void)
  • 返回值
    成功:pid号
    失败:-1

2). PPID

父进程号(Parent Process IDentification),是父进程的唯一标识,为一个正整数。

获取PPID的函数为:

  • 函数:getppid()
  • 作用
    获取父进程的PID
  • 头文件

        #include <unistd.h>
  • 函数原型

        pid_t getppid(void)
  • 返回值
    成功:pid号
    失败:-1

3). PGID

进程号(Parent Process IDentification),是父进程的唯一标识,为一个正整数。

获取PGID的函数为:

  • 函数:getpgid()
  • 作用
    获取本进程所属进程组的组号
  • 头文件

        #include <unistd.h>
  • 函数原型

        pid_t getpgid(pid_t pid)
  • 返回值
    成功:pgid号
    失败:-1

4. 进程管理

1). 创建进程 - fork

Linux的最初进程为init,PID为1,所有其它进程都是由该进程直接或间接创建。
创建进程常用函数为fork()vfork()

  • 函数:fork

    • 作用
      创建新的进程,被创建的进程为子进程,子进程复制父进程的几乎所有信息(所有用户空间信息和绝大多数内核空间信息),子进程独立于父进程的内存空间。
    • 头文件

          #include <unistd.h>
    • 函数原型

          pid_t fork(void)
    • 返回值
      成功:父进程中返回子进程的PID(正整数),子进程中返回0
      失败:-1

  • 函数:vfork

    • 作用
      同样是创建一个新进程
      fork的区别在于:创建进城后并不复制父进程的地址空间,而是在必要的时候才申请内存空间;即共享父进程的内存空间
    • 头文件

          #include <unistd.h>
    • 函数原型

          pid_t vfork(void)
    • 返回值
      成功:父进程中返回子进程的PID(正整数),子进程中返回0
      失败:-1

2). 运行新代码 - execX家族

fork()创建子进程后,在子进程中需要运行新的程序,则可以采用两种方式:

system(const char *cmd):   创建一个新的子进程执行cmd,执行完成后返回到父进程,为阻塞执行
execX家族:           不创建新进程,执行完成后,该语句执行完成后结束本进程

  • system

    • 头文件

          #include <stdlib.h>
    • 函数原型

          int system(const char* command)
    • 返回值
      成功:0
      失败:-1

  • execX 家族

    • 头文件

          #include <unistd.h>
    • 函数原型

    函数原型使用文件名(p) / 路径名使用参数表(l) / argv(v)
    execlint execl(const char *path, const char *arg, ...)l
    execlpint execlp(const char *file, const char *arg, ...)pl
    execleint execle(const char *path, const char *arg, ..., char * const envp[])l
    execvint execv(const char *path, char *const argv[])v
    execvpint execvp(const char *file, char *const argv[])pv
    execveint execvpe(const char *file, char *const argv[], char *const envp[])v
    • 参数

      • path: 欲执行的程序名(可不包括路径),在$PATH中查找
      • file: 欲执行的程序名(绝对路径)
      • argv[]: 参数列表
      • envp[]: 新执行程序的环境变量
      • ...: 执行程度的参数列表,最后一个参数必须为 (char *)NULL
    • 返回值
      成功:void
      失败:-1

3). 用户空间资源回收 - exit/return

用户空间资源回收由两个函数完成:

return:   退出当前函数,但并不退出当前进程(main函数除外)
exit:    退出当前进程,刷新流缓冲区,关闭所有I/O流

  • exit:

    • 头文件

          #include <stdio.h>      //for exit()    atexit()   on_exit()
          #include <unistd.h>     //for _exit()
    • 函数原型

    函数原型描述
    exitvoid exit(int status)调用 atexit() / on_exit() 函数后退出,刷新I/O缓冲区
    _exitvoid _exit(int status)不调用任何注册函数而直接退出,不处理标准I/O缓冲区
    atexitint atexit(void (*function)(void))注册一个回调函数,当执行exit时,优先执行回调函数
    on_exitint on_exit(void (*function)(int , void *), void *arg)同at_exit,只是增加了回调函数的参数值
    • 返回值
      成功:0 (atexit/on_exit)
      失败:非0值 (atexit/on_exit)

4). 内核空间资源回收 - wait

进程退出时,只是清除了用户空间资源,而PCB是由其父进程进行回收的,回收子进程PCB的函数为:wait()waitpid().

  • wait

    • 作用
      父进程阻塞等待子进程的状态变化,回收该子进程的内核进程资源
    • 头文件

          #include </usr/include/sys/wait.h>
    • 函数原型

    函数原型描述
    waitpid_t wait(int *status)父进程阻塞等待 任何一个 子进程完成后,回收其资源后退出
    waitpidpid_t waitpid(pid_t pid, int *status, int options)父进程阻塞等待 指定子进程 完成后,回收其资源后退出
    • 参数

      • pid: 子进程ID号
      PID描述
      PID>0等待该PID的进程结束
      PID=0等待与当前进程的进程组PGID一致的进程结束
      PID=-1等待任意子进程结束,相当于 wait()
      PID<-1等待进程组PGID等于该PID(绝对值)结束
      • status: 子进程退出时的状态信息
      • options:等待选项,一般设置为0,特殊情况请查阅man

5). 三种新进程启动方式比较:

启动方式特点
system()需要启动新的shell并在新的shell是执行子进程,所以对环境的依赖较大,而且效率也不高;
同时system函数要等待子进程的返回才能执行下面的语句。
execX()用新的进程来替换原先的进程,效率较高;
但它不会返回到原先的进程,也就是说在exec函数后面的所有代码都不会被执行,除非exec调用失败。
然而exec启动的新进程继承了原进程的许多特性,在原进程中已打开的文件描述符在新进程中仍将保持打开,
但需要注意,任何在原进程中已打开的目录流都将在新进程中被关闭。
fork()用当前的进程来复制出一个新的进程,新进程与原进程一模一样,执行的代码也完全相同;
但新进程有自己的数据空间、环境变量和文件描述符,
我们通常根据fork函数的返回值来确定当前的进程是子进程还是父进程,
即它并不像exec那样并不返回,而是返回一个pid_t的值用于判断,我们还可以继续执行fork后面的代码。
用fork与exec系列函数就能创建所需的进程。

5. 特殊进程

1). 孤儿进程

因父进程先退出而导致一个子进程被init收养,称该进程为孤儿进程
孤儿进程的父进程为init,该进程在孤儿进程退出后回收其PCB

2). 僵死(僵尸)进程

进程已经退出,但是其父进程尚未来得及回收其PCB资源,即其PCB资源还没有释放,成为 “Zomble

3). 守候进程

守候进程是在后台运行的一个特殊进程,它脱离于终端,可避免被终端所产生的信号打断;执行过程中的任何信息不在终端显示;周期性的执行某些任务或等待处理某些发生的事件。

其实,Linux上存在大量守候进程,如web,日志管理进程等。

转载于:https://www.cnblogs.com/Jimmy1988/p/7536160.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值