美文网首页
读者-写者问题的应用——多面墙的查询问题

读者-写者问题的应用——多面墙的查询问题

作者: 江俊广 | 来源:发表于2018-12-13 23:48 被阅读0次

    什么是读者-写者问题?

    读者-写者问题是指多个进程对一个共享资源即数据集(如文件或记录集)进行读写操作的问题。把只要求读数据的进程称为读进程,把要求修改数据的进程称为写进程。多个读进程可以同时读此数据集,不需要互斥也不会产生问题,不存在破坏数据完整性、正确性的问题,但是一个写进程不能与其他进程(不管是读进程还是写进程)同时访问此数据集,它们之间必须互斥,否则会破坏数据集的完整性。

    解决读者-写者问题的意义

    理论上,直接对数据集加锁,就可以实现对多进程时数据集的访问保护。但是在一段时间内并没有写进程,只有较多的读进程的话,对数据集的加锁是不必要的,反而会降低系统的性能。因此读者-写者问题的提出是为了在上述场景下,兼顾数据集访问安全和效率。

    读者-写者问题的解决方法

    分析

    多个读进程可以并发读数据集,因此用一个变量rc记录并发读数据集的进程数。当rc≥1时,禁止写进程对数据集进行写操作,当rc=0时,允许写进程对数据集进行写操作。

    rc对于读进程而言,是一个临界资源,因此设置一个互斥信号量mutex,防止多个读进程同时修改rc的值。

    数据集对于写进程而言是一个临界资源,因此设置一个互斥信号量db。

    相关变量总结

    • mutex: 保护对rc的访问,初值为1

    • db: 控制写进程对数据集的访问,初值为1

    • rc: 公共变量,记录读进程的个数

    同步算法

    Semaphore mutex=1;  //保护对rc的访问
    Semaphore db=1;  //控制对数据集的访问
    int rc=0;  //读数据集的读进程个数
    
    main()
    {
      Cobegin  //两个进程并发执行
        reader();
        writer();
       Coend
    }
    
    void reader()  //读者进程
    {
      while(true){
        P(mutex);  //互斥对rc的访问
        rc = rc + 1;  //增加一个读进程数
        if(rc == 1){  //当第一个读进程读数据集时,阻止写进程写
          P(db);
        }
        V(mutex);  //恢复对rc的访问
        读数据集
        P(mutex);  //互斥对rc的访问
        rc = rc - 1; //读者减少一个
        if(rc == 0){  //当最后一个读进程读完数据集时,允许写进程写
          V(db);
        }
        V(mutex);  //恢复对rc的访问
      }
    }
    
    void writer() //写者进程
    {
      while(true){
        P(db);  //排斥访问数据集
        写数据集;
        V(db);  //恢复对数据集的访问
      }
    }
    

    运行分析

    当一个读进程在使用数据集时,其他读进程也可以同时进行读操作,读进程的个数由rc来衡量。
    此时,如果有一个写进程到来,由于rc>0,因此写进程被挂起,知道所有读进程都结束时,写进程才可以开始写操作。

    当一个写进程在写操作时,其他进程(包括读进程和写进程)都会被挂起,直到当前写进程完成。

    上述算法确实可以解决读者-写者问题,当然也导致一个潜在的问题——只要有读进程陆续到来,写进程就会被一直挂起直到没有一个读进程为止,因此上述算法也被称为以读者为优先的算法。感兴趣的读者还可以查看以写者为优先的算法

    多面墙的查询问题

    笔者在实现弹幕系统的过程中遇到了如下问题。

    观众可以通过微信小程序发送弹幕到服务器。在服务器的数据库中,每条弹幕对应不同的记录,因此发送弹幕的请求不是互斥的。并且为了支持尽可能多的观众同时发送弹幕,发送弹幕的请求并发度需要比较高。

    与此同时,有n面弹幕墙向服务器查询最新的弹幕,在某一段时间内,这n面墙应该获取到相同的弹幕。由于n的大小是未知的,让每个弹幕记录是否被某一面墙查询过是比较困难的。因此我们让每一面墙维护一个最近查询时间last_query_time,当其向服务器发送查询请求时,服务器只会返回在last_query_time之后通过审核的弹幕。因此每个弹幕只需要记录审核时间checking_time即可。

    当服务器处理墙A的查询请求时,如果有新的弹幕B通过审核,则B在这次查询请求和下次查询请求中都不会返回给墙A。则弹幕B就被遗漏了。为了防止弹幕遗漏的发生,当墙A进行查询时,所有的发送弹幕请求都需要被挂起。而当有发送弹幕请求正在被处理时,所有的弹幕查询请求也需要被挂起。

    多面墙的查询问题的解决

    通过上述描述,读者不难发现多面墙的查询问题与读者-写者问题非常类似。
    发送弹幕请求对应读进程,请求数量多,并且彼此不互斥。
    查询弹幕请求对应写进程,请求数量少,并且当有查询弹幕请求时,不允许处理发送弹幕请求;当有发送弹幕请求时,不允许有查询弹幕请求。

    相关文章

      网友评论

          本文标题:读者-写者问题的应用——多面墙的查询问题

          本文链接:https://www.haomeiwen.com/subject/qdvihqtx.html