zoukankan      html  css  js  c++  java
  • 信号量(记录型,AND,信号量集)

    1.记录型信号量:为了解决整形信号量让权等待的问题,添加一个阻塞队列,记录型信号量完全符合进程同步准则

    (注意阻塞是进程主动的),当进程资源不够时,进程/线程进入阻塞队列

    程序计数器定位在wait之后:这句话的意思是,记录型信号量的p操作,总是先预先分配资源,当进程/线程资源满足时,从阻塞队列进入就绪队列调度

    执行时,不需要在重新分配资源了,因为提前预先分配了.当进程出来直接运行不用在分配资源了

    注意:这里wait和signal中参数不是int类型的,是semaphore类型的,我也不知道,为啥都写成int类型的,教科书上都这样写,具体编程时要注意.

     2.记录型信号量典型应用:注意,这里block,wake在linux中都没有,这里只是理论上的一个函数名字,下面我会讲linux下的p,v操作函数

     3.Linux下的pv操作

    补充:
    sem_t 是一种数据类型,用来定义记录型信号量的,内部含有阻塞队列
    sem_init函数是用来初始化记录型信号量的
    eg:
      sem_t a;
      sem_init(&a,0,1); //初始化一个只有一个资源的记录型信号量 wait相当于linux下的sem_wait,signal相当于linux下的sem_post
    信号量使用完,必须销毁,在主线程中使用sem_destroy函数销毁
    eg:
      seg_destroy(&a);

    4.实例:

    这个策略,什么信号量都适合使用,包括后面的AND信号量和信号量集,都是基于这个原理

    题目说明:盘子中一直只能有一个水果,实现同步

    题目分析:我们采用记录型信号量解决这个问题
      1.在问题域中找临界资源,
    发现爸爸,妈妈关注盘子资源是不是(为空)能放水果,所以盘子(plate)是临界资源
    女儿只关心能不能吃到苹果(apple),所以对女儿来说苹果是一个临界资源
    儿子只关心能不能吃到橘子(orange),所以对于儿子来说橘子就是一个临界资源
    所以临界资源有:plate,apple,orange
      2.为每一个临界资源定义一个信号量
      plate:盘子,初始时,只有1个
      apple:苹果,初始时,有0个
      orange:橘子,初始时,有0个

      3,4步在具体编程中使用,切记切记,一定遵循这个原则
    分析,父亲母亲(wait盘子,signal水果),占用盘子资源放水果,
        当儿子或女儿吃完水果时(wait水果,signal盘子),应该由儿子或女儿释放盘子资源
    综上,可是现题目中的同步

     源代码:

    //m4.cpp  创建方法:vim m4.cpp  编译方法:g++ m4.cpp -lpthread -o m4 执行方法: ./m4
    #include <stdio.h> #include <pthread.h> #include <semaphore.h> sem_t plate,orange,apple;//定义三个信号量
    //void* 表示返回值可以是任意类型的指针, 形参中的void *p表示传入的形参可以是任意类型的指针,可用于传递多个参数 void *father(void *p) //父亲函数,用于创建线程 { while(1) { sem_wait(&plate); //3,4原则,父亲线程先判断是不是有盘子资源 printf("the father put a apple "); sem_post(&apple); //父亲,放完苹果,盘子中苹果数目+1=1,如果你这里有疑问请看最上面signal函数的伪代码逻辑 } return NULL; } void *mother(void *p) //同理 { while(1) { sem_wait(&plate); printf("the mother put a orange "); sem_post(&orange); } return NULL; } void *daughter(void *p) { while(1) { sem_wait(&apple); //女儿判断盘子中是不是有苹果 printf("the daughter eats a apple "); sem_post(&plate); //女儿,吃完苹果后,应该释放盘子资源,为了父亲,母亲能在放水果 } return NULL; } void *son(void *p) { while(1) { sem_wait(&orange); printf("the son eats a orange "); sem_post(&plate); } return NULL; } int main() { sem_init(&plate,0,1);//初始化盘子临界资源,初始1个 sem_init(&orange,0,0);//初始化橘子临界资源,初始0个 sem_init(&apple,0,0);//初始化苹果临界资源,初始0个 pthread_t tid[4]; //创建四个进程 pthread_create(&tid[0],NULL,&father,NULL); pthread_create(&tid[1],NULL,&mother,NULL); pthread_create(&tid[2],NULL,&daughter,NULL); pthread_create(&tid[3],NULL,&son,NULL); pthread_join(tid[0],NULL); //主线程阻塞,等待子进程(线程执行),主线程不阻塞的话,会直接执行完 sem_destroy(&plate); //销毁信号量 sem_destroy(&apple); sem_destroy(&orange); return 0; }

    执行结果:死循环

     5.AND型信号量和信号量集

    进程/线程同步准则:这里不区分进程/线程,因为,引入了线程后线程就是资源调度的基本单位了,所以同步也可以指进程的线程同步
    1.空闲让进:
    2.忙则等待:
    3.有限等待
    4.让权等待:优先权低的进程让优先权高的的进程先执行
    AND型信号量:可以避免死锁
    为了解决一次分配多中资源,每种资源每次分配一个,一次获得进程所需要的所有资源(每种个1个),否则进程阻塞,是记录型信号量上的进一步延伸
    AND型信号量的阻塞队列机制,为每种资源设置一个阻塞队列,当最先出现资源不足的资源种类为Ri时,那么进程就被阻塞在Ri资源对应的阻塞队列中

    信号量集:申请n类资源,每类资源最低ti个,每类申请di个资源

    AND的进一步延伸,设置一个最低资源数目>=1,和进程需要的资源数目>=0

     

    6.记录型信号量和信号量集比较

     

  • 相关阅读:
    DRF
    DRF
    DRF
    DRF
    DRF
    DRF
    DRF
    Mongo错误记录:MongoClient opened before fork. Create MongoClient
    Hive默认分隔符和默认NULL值
    hdfs文件格式比较
  • 原文地址:https://www.cnblogs.com/nanfengnan/p/14929161.html
Copyright © 2011-2022 走看看