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

什么是读者-写者问题?

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

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

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

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

分析

多个读进程可以并发读数据集,因此用一个变量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进行查询时,所有的发送弹幕请求都需要被挂起。而当有发送弹幕请求正在被处理时,所有的弹幕查询请求也需要被挂起。

多面墙的查询问题的解决

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

你可能感兴趣的:(读者-写者问题的应用——多面墙的查询问题)