In
computer science
Computer science is the study of computation, automation, and information. Computer science spans theoretical disciplines (such as algorithms, theory of computation, information theory, and automation) to practical disciplines (includin ...
, the readers–writers problems are examples of a common computing problem in
concurrency
Concurrent means happening at the same time. Concurrency, concurrent, or concurrence may refer to:
Law
* Concurrence, in jurisprudence, the need to prove both ''actus reus'' and ''mens rea''
* Concurring opinion (also called a "concurrence"), a ...
. There are at least three variations of the problems, which deal with situations in which many concurrent
thread
Thread may refer to:
Objects
* Thread (yarn), a kind of thin yarn used for sewing
** Thread (unit of measurement), a cotton yarn measure
* Screw thread, a helical ridge on a cylindrical fastener
Arts and entertainment
* ''Thread'' (film), 2016 ...
s of execution try to access the same shared resource at one time.
Some threads may read and some may write, with the constraint that no thread may access the shared resource for either reading or writing while another thread is in the act of writing to it. (In particular, we want to prevent more than one thread modifying the shared resource simultaneously and allow for two or more readers to access the shared resource at the same time). A
readers–writer lock
In computer science, a readers–writer (single-writer lock, a multi-reader lock, a push lock, or an MRSW lock) is a synchronization primitive that solves one of the readers–writers problems. An RW lock allows concurrent access for read-onl ...
is a
data structure
In computer science, a data structure is a data organization, management, and storage format that is usually chosen for Efficiency, efficient Data access, access to data. More precisely, a data structure is a collection of data values, the rel ...
that solves one or more of the readers–writers problems.
The basic reader–writers problem was first formulated and solved by Courtois ''et al.''
First readers–writers problem
Suppose we have a shared memory area (critical section) with the basic constraints detailed above. It is possible to protect the shared data behind a mutual exclusion
mutex
In computer science, a lock or mutex (from mutual exclusion) is a synchronization primitive: a mechanism that enforces limits on access to a resource when there are many threads of execution. A lock is designed to enforce a mutual exclusion concu ...
, in which case no two threads can access the data at the same time. However, this solution is sub-optimal, because it is possible that a reader ''R
1'' might have the lock, and then another reader ''R
2'' requests access. It would be foolish for ''R
2'' to wait until ''R
1'' was done before starting its own read operation; instead, ''R
2'' should be allowed to read the resource alongside ''R
1'' because reads don't modify data, so concurrent reads are safe. This is the motivation for the first readers–writers problem, in which the constraint is added that ''no reader shall be kept waiting if the share is currently opened for reading.'' This is also called readers-preference, with its solution:
semaphore resource=1;
semaphore rmutex=1;
readcount=0;
/*
resource.P() is equivalent to wait(resource)
resource.V() is equivalent to signal(resource)
rmutex.P() is equivalent to wait(rmutex)
rmutex.V() is equivalent to signal(rmutex)
*/
writer()
reader()
In this solution of the readers/writers problem, the first reader must lock the resource (shared file) if such is available. Once the file is locked from writers, it may be used by many subsequent readers without having them to re-lock it again.
Before entering the
critical section
In concurrent programming, concurrent accesses to shared resources can lead to unexpected or erroneous behavior, so parts of the program where the shared resource is accessed need to be protected in ways that avoid the concurrent access. One way ...
, every new reader must go through the entry section. However, there may only be a single reader in the entry section at a time. This is done to avoid
race condition
A race condition or race hazard is the condition of an electronics, software, or other system where the system's substantive behavior is dependent on the sequence or timing of other uncontrollable events. It becomes a bug when one or more of t ...
s on the readers (in this context, a race condition is a condition in which two or more threads are waking up simultaneously and trying to enter the critical section; without further constraint, the behavior is nondeterministic. E.g. two readers increment the readcount at the same time, and both try to lock the resource, causing one reader to block). To accomplish this, every reader which enters the
will lock the for themselves until they are done with it. At this point the readers are not locking the resource. They are only locking the entry section so no other reader can enter it while they are in it. Once the reader is done executing the entry section, it will unlock it by signalling the mutex. Signalling it is equivalent to: mutex.V() in the above code. Same is valid for the . There can be no more than a single reader in the exit section at a time, therefore, every reader must claim and lock the Exit section for themselves before using it.
Once the first reader is in the entry section, it will lock the resource. Doing this will prevent any writers from accessing it. Subsequent readers can just utilize the locked (from writers) resource. The reader to finish last (indicated by the readcount variable) must unlock the resource, thus making it available to writers.
In this solution, every writer must claim the resource individually. This means that a stream of readers can subsequently lock all potential writers out and starve them. This is so, because after the first reader locks the resource, no writer can lock it, before it gets released. And it will only be released by the last reader. Hence, this solution does not satisfy fairness.
Second readers–writers problem
The first solution is suboptimal, because it is possible that a reader ''R1'' might have the lock, a writer ''W'' be waiting for the lock, and then a reader ''R2'' requests access. It would be unfair for ''R2'' to jump in immediately, ahead of ''W''; if that happened often enough, ''W'' would starve
Starvation is a severe deficiency in caloric energy intake, below the level needed to maintain an organism's life. It is the most extreme form of malnutrition. In humans, prolonged starvation can cause permanent organ damage and eventually, dea ...
. Instead, ''W'' should start as soon as possible. This is the motivation for the second readers–writers problem, in which the constraint is added that ''no writer, once added to the queue, shall be kept waiting longer than absolutely necessary''. This is also called writers-preference.
A solution to the writers-preference scenario is:
int readcount, writecount; //(initial value = 0)
semaphore rmutex, wmutex, readTry, resource; //(initial value = 1)
//READER
reader()
//WRITER
writer()
In this solution, preference is given to the writers. This is accomplished by forcing every reader to lock and release the readtry semaphore individually. The writers on the other hand don't need to lock it individually. Only the first writer will lock the readtry and then all subsequent writers can simply use the resource as it gets freed by the previous writer. The very last writer must release the readtry semaphore, thus opening the gate for readers to try reading.
No reader can engage in the entry section if the readtry semaphore has been set by a writer previously. The reader must wait for the last writer to unlock the resource and readtry semaphores. On the other hand, if a particular reader has locked the readtry semaphore, this will indicate to any potential concurrent writer that there is a reader in the entry section. So the writer will wait for the reader to release the readtry and then the writer will immediately lock it for itself and all subsequent writers. However, the writer will not be able to access the resource until the current reader has released the resource, which only occurs after the reader is finished with the resource in the critical section.
The resource semaphore can be locked by both the writer and the reader in their entry section. They are only able to do so after first locking the readtry semaphore, which can only be done by one of them at a time.
It will then take control over the resource as soon as the current reader is done reading and lock all future readers out. All subsequent readers will hang up at the readtry semaphore waiting for the writers to be finished with the resource and to open the gate by releasing readtry.
The rmutex and wmutex are used in exactly the same way as in the first solution. Their sole purpose is to avoid race conditions on the readers and writers while they are in their entry or exit sections.
Third readers–writers problem
In fact, the solutions implied by both problem statements can result in starvation — the first one may starve writers in the queue, and the second one may starve readers. Therefore, the third readers–writers problem is sometimes proposed, which adds the constraint that ''no thread shall be allowed to starve''; that is, the operation of obtaining a lock on the shared data will always terminate in a bounded amount of time.
A solution with fairness for both readers and writers might be as follows:
int readcount; // init to 0; number of readers currently accessing resource
// all semaphores initialised to 1
semaphore resource; // controls access (read/write) to the resource. Binary semaphore.
semaphore rmutex; // for syncing changes to shared variable readcount
semaphore serviceQueue; // FAIRNESS: preserves ordering of requests (signaling must be FIFO)
//READER
reader()
//WRITER
writer()
This solution can only satisfy the condition that "no thread shall be allowed to starve" if and only if semaphores preserve first-in first-out ordering when blocking and releasing threads. Otherwise, a blocked writer, for example, may remain blocked indefinitely with a cycle of other writers decrementing the semaphore before it can.
Simplest reader writer problem
The simplest reader writer problem which uses only two semaphores and doesn't need an array of readers to read the data in buffer.
Please notice that this solution gets simpler than the general case because it is made equivalent to the Bounded buffer problem, and therefore only readers are allowed to enter in parallel, being the size of the buffer.
Reader
do while (TRUE);
Writer
do while (TRUE);
Algorithm
# Reader will run after Writer because of read semaphore.
# Writer will stop writing when the write semaphore has reached 0.
# Reader will stop reading when the read semaphore has reached 0.
In writer, the value of write semaphore is given to read semaphore and in reader, the value of read is given to write on completion of the loop.
See also
* ABA problem
In multithreaded computing, the ABA problem occurs during synchronization, when a location is read twice, has the same value for both reads, and "value is the same" is used to indicate "nothing has changed". However, another thread can execute be ...
* Producers-consumers problem
* Dining philosophers problem
In computer science, the dining philosophers problem is an example problem often used in concurrent algorithm design to illustrate synchronization issues and techniques for resolving them.
It was originally formulated in 1965 by Edsger Dijkstr ...
* Cigarette smokers problem
The cigarette smokers problem is a concurrency problem in computer science, originally described in 1971 by Suhas Patil. The problem has been criticized for having "restrictions which cannot be justified by practical considerations."
Problem des ...
* Sleeping barber problem In computer science, the sleeping barber problem is a classic inter-process communication and synchronization problem that illustrates the complexities that arise when there are multiple operating system processes.
The problem was originally prop ...
* Readers–writer lock
In computer science, a readers–writer (single-writer lock, a multi-reader lock, a push lock, or an MRSW lock) is a synchronization primitive that solves one of the readers–writers problems. An RW lock allows concurrent access for read-onl ...
* seqlock
A seqlock (short for ''sequence lock'') is a special locking mechanism used in Linux for supporting fast writes of shared variables between two parallel operating system routines. The semantics stabilized as of version 2.5.59, and they are present ...
* read-copy-update In computer science, read-copy-update (RCU) is a synchronization mechanism that avoids the use of lock primitives while multiple threads concurrently read and update elements that are linked through pointers and that belong to shared data structu ...
References
*Morris JM (1979). A starvation-free solution to the mutual exclusion problem. Inf Process Lett 8:76–80
*Fair Solution to the Reader-Writer-Problem with Semaphores only. H. Ballhausen, 2003
*Faster Fair Solution for the Reader–Writer Problem. V. Popov, O. Mazonka 2013
External links
Algorithmic description of the third readers–writers problem
{{DEFAULTSORT:Readers-writers problem
Concurrency (computer science)