进程基础知识

进程

  • 进程:是动态正在运行程序系统分配资源的最小单位。 系统最多只能同时运行与处理器数相同的任务数
  • SMP :对称多处理 处理器通过调度算法执行任务
  • 时间片: 根据不同进程分配一个合适执行时间片(每个进程的时间片不同).由于时间片的时间太短人几乎感觉不到时间差

进程状态

  • 进程准备运行或运行(running 进程进入到准备运行队列中)
  • 2.堵塞(block)
    • a.等待:可中断堵塞,可以接收硬件响应或系统信 号,唤醒之后可以进入到准备运行队列
    • b.睡眠:不中终端堵塞,可以接收硬件响应但不能接收系统信号,睡眠状态不能直接进入到准备运行队列
  • 停止状态(stop)
  • .僵死状态():进程结束释放部分资源,但在父进程的子进程链表中仍然存在子进程节点

进程地址空间结构

  • 代码段 存储代码和字面常量,属于只读区域不能修改
  • 数据段 初始化的全局和静态变量
  • BSS段 未初始化的全局和静态变量
  • 用户自己分配释放
  • 共享区(文件内存映射区)
  • 函数参数值,局部变量,返回地址等 高地址–>低地址
  • 命令行参数和环境变量
  • 内核空间 在32 位系统中(进程地址空间大小为4G 用户空间3G(0-3) 内核空间1G(3-4))

进程编程

fork

  • __pid_t fork(); 从fork函数成功返回之后,就存在两个进程, 调用clone函数 完全复制父进程虚拟地址空间,依据COW 写时复制
    返回值 pid=0:子进程中获取值
    pid>0:父进程中获取值
    pid==-1:失败(内存不够)

    fork成功返回 父子进程执行顺序不定,/proc/sys/kernel/sched_child_runs_first 内核设置子进程线运行配置文件 (0 父进程先执行 1 子进程先执行)

  • 写时复制 当父或子进程修改值之前复制到另外一个进程.

  • 子进程复制父进程:(复制内容)
    数据段 栈 打开文件描述符 资源限制 实际用户id 有效用户id 实际用户组id 有效用户id 进程组id

  • 子进程不复制父进程内容:
    代码段共用 资源当前使用值请0 进程id CPU使用时间 未抵达的信号 内存锁 记录锁 记录锁 定时器(alarm timer) 信号量
    子进程id是通过进程id hash表中从小到大分配一个未使用的值.

  • 子进程先执行能在一定程度上避免写时复制 提高效率和内存利用率

    chen@ubuntu:~/work$ cat /proc/sys/kernel/sched_child_runs_first 
    0
    chen@ubuntu:~/work$ 
    系统配置父进程先执行
    int main(int argc,const char* argv[])
    {
         
        printf("parent  process is running\n");
        printf("parent pid=%d\n",getpid());//获取正在被执行进程ID值
        pid_t pid=fork();
        if(pid==-1)
        {
         
            perror("fork error\n");
        }
        if(pid==0)
        {
         
            //子进程执行语句       
            printf("child pid=%d\n",getpid());
        }
        if(pid>0)
        {
         
           //父进程执行语句
           printf("pid=%d\n",pid);
           printf("parent pid=%d\n",getpid());
        }
        //父子进程执行语句
        printf("running end\n");
        return 0;
    }
    运行结果
        parent  process is running
        parent pid=3815
        pid=3816
        parent pid=3815
        parent running end
        child pid=3816
        parent running end
    
    修改配置文件 为1 
    运行结果
     	parent  process is running
        parent pid=3848
        pid=3849
        parent pid=3848
        parent running end
        child pid=3849
        parent running end
    
        
    
    

    vfork

    • 父子进程共用进程地址空间

    • 父进程堵塞,直到子进程结束,父进程唤醒

    • 进程间值的修改会有影响

    • 子进程 必须调用exit函数否则出现段错误

      int main(int argc, char const *argv[])
      {
             
      	int data=300;
      	printf("child  parent process id=%d:\n",getppid());
      
      	pid_t pid=vfork();
      	if(pid==0)
      	{
             
      		printf("child process running:\n");
              data=600;
              printf("child  parent process id=%d:\n",getppid());
              printf("child process data=%d:\n",data);
              // while(1)
              // {
             
      
              // }
              printf("child process data=%d:\n",data);
              printf("child  parent process id=%d:\n",getppid());
              //exit(0); /
      	}
          ///
          //子进程公用父进程栈空间,子进程不调用exit函数切换导致子进程运行结束释放栈,父进程开始运行,访问一个不存在栈空间
      	if(pid>0)
      	{
             
      		printf("------------parent process running:\n");
              printf("child process data=%d:\n",data);
      	}
      	return 0;
      }
      

    孤儿进程

    子进程未结束,父进程结束。

    僵尸进程

    • 概念:父进程未调用wait/waitpid,未收到子进程结束信号
    • 如何避免
      • 进程调用wait/waitpid
      • 在信号处理函数中调用wait/waitpid
      • 父进程忽略SIGCHLD,让内核处理

进程间通信

进程资源中的名词概念

  • 临界资源 一个时刻只能被一个进程修改的资源

  • 临界区 修改访问临街资源的语句

  • 进程同步 让多个进程有序访问临界资源

  • 进程互斥 同一时刻只能有一个进程访问临界资源,其他进程堵塞,进程访问资源是无序的

  • 进程并发 (单核)多个进程合作完成某个操作,但是一个时刻只能有一个进程执行

  • 进程并行 (多核)一个时刻有多个进程同时执行

  • **进程异步 ** 一个进程未结束另一个进程可以执行,回调函数实现进程异步操作

  • 是原子类型执行原子操作的变量

  • 死锁:多个进程构成资源的相互等待.

    • 发生死锁的原因:
      1.系统资源不足
      2.进程执行顺序不合适
      3.资源分配不均
    • 发生死锁的必要性:
      1.互斥性
      2.坚持性(占用资源之后,坚持占有)
      3.不可剥夺性(资源不能被抢占)
      4.循环等待性
    • 如何避免死锁发生:
      1.资源均匀分配
      2.合理安排进程执行顺序
      3.合理阻止循环等待
      4.可以实现资源抢断
  • 进程同步互斥的方式
    - 互斥锁
    - 大内核锁
    - 读写锁
    - 自旋锁 内核中的一种锁,当资源已经被锁住,进程不堵塞,继续运行,消耗CPU,等待解锁,只能适合较短的操作
    - 缺点:消耗CPU, 容易出现死锁
    - 优点:避免进程执行数据换入换出(CPU寄存器的数据域恢复
    - 信号
    - 信号量 内核中的一种锁,是通过 P,V 操作一个资源数记录变量,如果是P操作消耗资源资源记录数减一,当资源记录数<=0时,请求消耗资源的进程堵塞,如果是V操作,资源记录数加1

  • **中断 ** 中断电路发送电平信号给中断控制器,中断控制器通知CPU(控制器)停止执行当前的指令

    • 中断服务函数(程序)的特点:
      1.快速执行结束,不能堵塞,睡眠.
      2.没有返回类型
      3.interrupt 修饰
      4.没有参数
      5.不能有输出
      6.中断函数不能使用浮点数
    • 中断函数作用(用途):
      1.主要解决外围的响应速度比不上内核(处理器 CPU)的执行速度.提高CPU的利用率
      2.快速执行终端的服务程序,随时可能执行中断程序,解决了(polling)轮询执行弊端
      3.中断的保护(保存当前数据CPU寄存器值,栈)与终端的恢复(影响效率进程上下文的换入换出)
  • 原子类型:内核定义(锁级别的变量数据类型)类型(atomic_t)对原子类型的变量必须进行原子性操作(原子类型与硬件设备相关)、

  • 原子型操作:执行语句不可中断的操作

进程间通信方式

  • 管道;

    • 匿名管道 (pipe) :在内核划分一块内存,具有文件inode节点值,又不是一个物理文件,可以用文件操作方式(文件描述符)操作管道.

      • 匿名管道特点:
        1.只能实现具有亲属关系的进程(fork创建)
        2.传输数据是无格式,字节流.传输数据量不能太大.
        3.分为读端/写端
        4.半双工工作模式(单向传递)
        5.如果写端未关闭(存在写进程),读一个空的管道,读进程堵塞如果写端已关闭(写进程结束),读一个空的管道,读进程立即结束(读取函数返回值为0)
        6.如果读端未关闭(存在读进程),写一个满管道,写进程堵塞如果读端关闭(读进程结束),写进程继续写数据,内核发送一个SIGPIPE信号,此信号默认动作结束写进程
        7.读取管道数据后,数据被清空

      • 匿名管道实现双向通信

        /*
        用匿名管道实现进程的双向通信  创建的管道为半双工工作模式
        创建两个管道实现双向通信
        */
        int main(int argc, char const *argv[])
        {
                 
            int pipe_fd[2],pipe_fd1[2];
            pipe(pipe_fd);
            pipe(pipe_fd1);
            pid_t pid=fork();
            if(pid==
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值