前言:
此刻你们对“数据库只能读数据不能写数据”大约比较关怀,朋友们都想要知道一些“数据库只能读数据不能写数据”的相关资讯。那么小编在网摘上汇集了一些对于“数据库只能读数据不能写数据””的相关文章,希望大家能喜欢,大家快快来了解一下吧!进程同步问题是一个非常重要且相当有趣的问题,本篇我们对其中比较有名的读者-写者问题来进行学习。
问题描述
假设一个数据库为多个并发进程所共享。有的进程可能只需要读数据库,而另一些进程可能更新(即读和写)数据库。为了区分这两种类型的进程,我们称前者为读者(Reader),称后者为写者(Writer)。显然,如果多个读者同时访问共享数据,而不会产生副作用。但如果某个写者和其他进程(或读者或写者)同时访问数据库时可能导致数据不一致的错误。
为了确保不会出现数据不一致的问题,要求写者在写入数据库时具有共享数据库独占的访问权限。这一同步问题称为读者-写者问题(reader-writer problem)。
所以读者-写者问题要求:
允许多个读者同时执行读操作;不允许多个写者同时操作;不允许读者、写者同时操作。解决策略
读者-写者问题要解决: 读、读共享;写、写互斥;写、读互斥。
写者是比较简单的,它与任何线程互斥,用互斥信号量的 P操作、V 操作即可解决。
读者的问题比较复杂,它必须实现与写者的互斥,多个读者还可以同时读。仅仅简单的一对P操作、V操作是无法解决的。
可以有三种策略:读者优先、写者优先、读写公平。
读者优先
读进程只要看到有其他读进程正在访问文件,就可以继续作读访问;写进程必须等待所有读进程都不访问时才能写文件,即使写进程可能比一些读进程更早提出申请。可以使用一个计数器read_count记录读者总数目(包含等待和正在读的数目),如果read_count > 0 则写者等待,而读者直接读。当read_count = 0 写者与写者、写者与第一个读者抢占读写操作,这可以用一个二元信号量rw_mutex进行互斥访问。因为多个读者线程都要访问计数器,则使用一个二元信号量mutex进行互斥访问。
需要用到的共享变量:
int read_count = 0; // 系统当前读者进程数量semaphore rw_mutex = 1; // 读者与写者互斥访问共享数据的互斥信号量 semaphore mutex = 1; // 多个读者进程互斥修改当前读者进程数量的信号量
写者进程结构
do { P(rw_mutex); ... /* 修改共享数据 */ ... V(rw_mutex);}while(true);
读者进程结构
do { P(mutex); //获取修改读者进程数量的互斥信号量,该操作在请求rw_mutex之前,防止出现死锁 read_count++; if(read_count == 1) //判断当前是否为第一个读者进程 P(rw_mutex); //如果是就需要请求访问共享数据的互斥信号量 V(mutex); //read_count修改后 释放信号量 ... /* 读取数据 */ ... P(mutex); //获取修改读者进程数量的互斥信号量 read_count--; if(read_count == 0) //判断当前进程是否为最后一个读者进程 V(rw_mutex); //如果是则释放共享数据的互斥信号量,以允许写者进程操作共享数据 V(mutex);}while(true);
读者优先有可能导致写者进程产生饥饿现象,当系统中不断出现读者进程时,写者进程始终无法进入临界区。
写者优先
需要用到的共享变量:
int read_count = 0; // 系统当前读者进程数量int write_count = 0; // 系统当前写者进程数量semaphore rw_mutex = 1; // 读者与写者互斥访问共享数据的互斥信号量semaphore r_mutex = 1; // 互斥修改当前读取文件的进程数semaphore w_mutex = 1; // 互斥修改当前修改文件的进程数semaphore enter_mutex = 1; // 获取申请访问文件的权限
写者进程结构
do { P(w_mutex); //P操作 新的写者进程进入,上锁进行写者计数更新 write_count++; //更新写者计数器 if(write_count == 1) // 判断当前是否为第一个写者进程 P(enter_mutex); //P操作 则抢enter_mutex的锁,阻断后续到达的读者进程 V(w_mutex); //V操作 P(rw_mutex); //获取访问文件的权限,文件可能被其它写者进程占用,或者等待最后一个读者进程释放 ... /* 修改数据 */ ... V(rw_mutex); P(w_mutex); write_count--; if(write_count == 0) // 当所有写者进程都放弃使用文件时,运行读者进程申请访问文件 V(enter_mutex); V(w_mutex);}while(true);
读者进程结构
do { P(enter_mutex); // 获取申请访问文件的权限 P(r_mutex); //上锁进行读者计数更新 read_count++; //更新读者计数器 if(read_count == 1) // 判断当前是否为第一个读者进程 P(rw_mutex); // 占用文件 V(r_mutex); V(enter_mutex); // ... /* 读取数据 */ ... P(r_mutex); read_count--; if(read_count == 0) P(rw_mutex); // 释放文件 P(r_mutex);}while(true);
写者优先有可能导致读者进程产生饥饿现象,当系统中不断出现写者进程时,读者进程始终无法进入临界区。
读写公平
需要用到的共享变量:
int read_count = 0; // 系统当前读者进程数量semaphore rw_mutex = 1; // 读者与写者互斥访问共享数据的互斥信号量semaphore r_mutex = 1; // 互斥修改当前读取文件的进程数semaphore enter_mutex = 1; // 获取申请访问文件的权限
写者进程结构
do { P(enter_mutex); // 阻断后续到达的读者进程 P(rw_mutex); ... /* 修改数据 */ ... V(rw_mutex); V(enter_mutex); }while(true);
读者进程结构
do { P(enter_mutex); // 获取申请访问的权限,这里与写者优先的区别在于,写者放弃占用文件时,所有读者 都可以与写者进程进行再次竞争 P(r_mutex); read_count++; if(read_count == 1) // 判断当前是否为第一个读者进程 P(rw_mutex); signal(r_mutex); signal(enter_mutex); // 释放许可,其余读者和写者进程将进行下一轮竞争 ... /* 读取数据 */ ... wait(r_mutex); read_count--; if(read_count == 0) signal(rw_mutex); signal(r_mutex);}while(true);
上面的代码的 读者进程结构其实和第二个写者优先的 读者进程结构 是一样的,不一样的是写者进程结构。写者进程变成在每次写操作前都要等待 enter_mutex信号量。这里的P(enter_mutex) P操作并不会出现写者优先,而是按照先进先出的顺序让读者写者使用资源。
标签: #数据库只能读数据不能写数据