Linux进程控制

基础概念

什么是进程?

进程是一个具有一定独立功能的程序的一次运行活动 
进程是一个程序正在执行的实例。每个这样的实例都有自己的地址空间执行状态

进程执行状态
  • 执行状态 
    进程正在占用CPU。
  • 就绪状态 
    进程已具备一切条件,等待分配CPU。
  • 等待状态 
    进程不能使用CPU,若等待的事件发生则可将其唤醒。
  • 进程ID

    每个进程都有一个ID(ID是一个正整数),唯一标识了系统中的这个进程。 
    每个进程都有一个创建它的进程,叫父进程(Parent Process)

    • 进程ID(PID):标识进程的唯一数字

    • 父进程ID(PPID)

    • 启动进程的用户ID(UID)

    进程生命周期
    • 创建 
      每个进程都由其父进程创建。父进程可以创建子进程,子进程又可以创建子进程的子进程。
    • 运行 
      多个进程可以同时存在,进程之间可以进行通信。
    • 终止 
      结束一个进程的运行。
    进程特点

    动态性,并发性,独立性,异步性

    进程互斥

    当有若干进程都要使用某一共享资源时,任何时候最多允许一个进程使用,其他要使用该资源的进程必须等待,直到占用该资源者释放了该资源为止

    临界资源

    操作系统中将一次只允许一个进程访问的资源称为临界资源

    临界区

    进程中访问临界资源的那段程序代码称为临界区。为实现对临界资源的互斥访问,应保证诸进程互斥的进入各自的临界区

    进程同步

    一组并发进程按一定的顺序执行的过程称为进程间的同步。 
    具有同步关系的一组并发进程称为合作进程,合作进程间互相发送的信号称为消息或事件

    进程调度
    • 概念: 
      按一定算法,从一组待运行的进程中选出一个来占有CPU运行。

    • 调度方式:

      • 抢占式
      • 非抢占式
    进程死锁

    多个进程因竞争资源而形成一种僵局,若无外力作用,这些进程都将永远不能再向前推进

    进程控制编程

    获取ID
    #include <sys/types.h>
    #include <unistd.h>
    
    获取本进程ID
    pid_t getpid(void);
    
    获取父进程ID
    pid_t getppid(void);

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    
    int main()
    {
         printf ("PID = %d\n", getpid());
         printf ("PPID = %d\n", getppid());
    进程创建fork()
    #include <unistd.h> 
    pid_t fork(void)
    • 1
    • 2
    功能:创建子进程

    fork的奇妙之处在于它被调用一次,却返回两次,它可能有三种不同的返回值: 
    1. 在父进程中,fork返回新创建的子进程的PID; 
    2. 在子进程中,fork返回0; 
    3. 如果出现错误,fork返回一个负值

    说明
    • 当fork()顺利完成任务时,就会存在两个进程,每个进程都从fork()返回处开始继续执行。
    • 两个进程执行相同的代码(text)段,但是有各自的堆栈(stack)段、数据(data)段以及堆(heap)。
    • 子进程的stack、data、heap segments是从父进程拷贝过来的。
    • fork()之后,哪一个进程先执行(scheduled to use the CPU)不确定。
    进程的终止

    下面两个函数都用于正常终止一个进程:

    _exit:立即进入内核 
    exit:先执行一些清理处理(调用各终止处理程序、关闭所有标准I/O流等),然后进入内核。

    #include <stdlib.h>
    void exit(int status);
    #include <unistd.h>
    void _exit(int status);

    这两个函数都有一个整型参数,称之为终止状态(exit status)。

    exec函数族

    exec用被执行的程序替换调用它的程序

    fork与exec的区别:
    • fork 创建一个新的进程,产生一个新的PID
    • exec 启动一个新程序,替换原有的进程,因此进程的PID不会改变
    execl
    #include <unistd.h>
    
    int execl(const char * path, const char* arg1,...)

    参数: 
    path : 被执行程序名(含完整路径) 
    arg1 - argn: 被执行程序所需的命令行参数,含程序名。以空指针(NULL)结束

    #include <stdio.h>
    #include <unistd.h>
    
    int main()
    {
      execl ("/bin/ls", "ls", "-al", "/home", NULL);
    
      return 0;
    }
    execv
    #include <unistd.h>
    
    int execv(const char * path, const argv[])

    参数: 
    path : 被执行程序名(含完整路径)。 
    argv[]: 被执行程序所需的命令行参数数组。

    进程等待
    • 问题 
      父进程创建子进程后,如何知道子进程什么时候终止?如何知道子进程怎么终止(正常or异常)?

    • 措施 
      wait()或waitpid()

    #include <sys/wait.h>
    pid_t wait(int *status);
    pid_t waitpid(pid_t pid, int *status, int options); 
    返回值:若成功返回进程ID,若出错返回-1
    调用wait或waitpid的进程可能发生的情况有:
    • 如果所有子进程都还在运行,则阻塞(Block)。
    • 如果一个子进程已终止,正等待父进程获取其终止状态,则取得该子进程的终止状态立即返回。
    • 如果它没有任何子进程,则立即出错返回。
    • 在一个子进程终止前,wait使其调用者阻塞,而waitpid有一个选项,可使调用者不阻塞。
    • waitpid并不等待在其调用之后的第一个终止的子进程。它有若干个选项,可以控制它所等待的进程。
    • 如果一个子进程已经终止,并且是一个僵死进程,wait立即返回并取得子进程的状态,否则wait使其调用者阻塞直到一个子进程终止。如果调用者阻塞并且它有多个子进程,则在其一个子进程终止时,wait就立即返回。因为wait返回终止子进程的ID,所以总能了解到是哪一个子进程终止了。

    注:僵死进程(zombie),一个已经终止、但是其父进程尚未对其进行善后处理(获得终止子进程的有关信息,释放它仍占用的资)的进程被称为僵死进程。

    终止状态

    有4个互斥的宏可以用来获取进程终止的原因:

    • WIFEXITED(status) 
      若子进程正常终止,该宏返回true。 
      此时,可以通过WEXITSTATUS(status)获取子进程的退出状态(exit status)。

    • WIFSIGNALED(status) 
      若子进程由信号杀死,该宏返回true。 
      此时,可以通过WTERMSIG(status)获取使子进程终止的信号值。

    • WIFSTOPPED(status) 
      若子进程被信号暂停(stopped),该宏返回true。 
      此时,可以通过WSTOPSIG(status)获取使子进程暂停的信号值。

    • WIFCONTINUED(status) 
      若子进程通过SIGCONT恢复,该宏返回true。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值