读者-写者问题
哲学家问题对于多个竞争进程互斥地访问有限资源(如I/O设备)这一类问题的建模十分有用。另一个著名的问题是读者-写者问题,它为数据库访问建立了一个模型。例如,设想一个飞机定票系统,其中有许多竞争的进程试图读写其中的数据。多个进程同时读是可以接受的,但如果一个进程正在更新数据库,则所有其他进程都不能访问数据库,即使读操作也不行。这里的问题是:如何对读者和写者进行编程?图2-19给出了一种解法。
typedef int semaphore; semaphore mutex=1; /* 控制对RC的访问 */ semaphore db=1; /* 控制对数据库的访问 */ int rc=0; /* 正在读或想要读的进程数 */ void reader(void) { while(TRUE){ /* 无限循环 */ down(&mutex); /* 排斥对RC的访问*/ rc = rc+1; /*又多了一个读者*/ if(rc == 1) down(&db); /*如果这是第一个读者,那么......*/ up(&mutex); /*恢复对RC的访问*/ read_data_base(); /*访问数据*/ down(&mutex); /*排斥对RC的访问*/ rc = rc -1; /*读者又少了一个*/ if(rc==0) up(&db); /*如果这是最后一个读者,那么......*/ use_data_read(); /*非临界区操作*/ } } void writer(void) { while(TRUE) { think_up_data(); /*非临界区操作*/ down(&db); /*排斥访问*/ write_data_base(); /*修改数据*/ up(&db); /*恢复访问*/ } } 图2-19 一个读者与作者问题的解决方案
第一个读者对信号量db执行DOWN。随后的读者只是递增一个计数器rc。当读者离开时,它们递减这个计数器,而最后一个读者则对db执行UP,这样就允许一个阻塞的写者可以访问数据库。
设想当一个读者在使用数据库时,另一个读者也来访问数据库,由于同时允许多个读者同时进行读操作,所以第二个读者也被允许进入,同理第三个及随后更多的读者都被允许进入。
现在假设一个写者到来,由于写操作是排他的,所以它不能访问数据库,而是被挂起。随后其他的读者到来,这样只要有一个读者活跃,随后而来的读者都被允许访问数据库。这样的结果是只要有读者陆续到来,它们一来就被允许进入,而写者将一直被挂起直到没有一个读者为止。假如每2秒钟来一个读者,而其操作时间为5秒钟,则写者将永远不能访问数据库,或者我们说写者发生了饥饿现象。这就是读者优先的解法。