Readers-Writers Problem and WINCACHE
This is a very common problem which most of us has studied in our academic days. This we learn as part of process synchronization or concurrency. For the sake of this discussion let’s assume we have multiple process accessing common data in a shared memory (ideally a common shared resource is available). While some processes will read from the shared memory, all others may write to it. While we can allow multiple readers to read from shared memory as it does not harm, there can be no time where more than one writer can have access to shared memory or a writer as well as a reader can have access to shared memory simultaneously.
This means from the above problem we will need to do the following:
- There is no reader/writer and a writer comes. Writer should get the write lock and continue.
- Reader comes and someone is already writing. Wait till the write is done and then continue. Increment the number of reader count.
- There is no reader/writer and reader comes. Reader should acquire write lock and set reader count to 1. Whenever the reader count goes to 0, release the write lock. This will ensure that multiple readers are allowed to read but if a writer comes it will have to wait unless all reader is done.
It does have a potential that readers may starve writers by denying them access to shared resource forever. Nonetheless this is beyond the scope of this discussion and is not relevant here. For the sake of simplicity we will assume that shared memory access will be fairly divided between readers and writers.
However you must be thinking it is a synchronization problem and if not implemented properly you may end up with a race condition. Then why am I talking about this with respect to WINCACHE. Yes it is a process synchronization problem which all of us has studied in our academic days. There are many other variants of the same problem like Dining Philosopher’s Problem, Producer Consumer Problem. These are all process synchronization problem and a bad implementation can lead to some kind of race condition.
But what has WINCACHE to do with this? The reason I am talking about this is because with WINCACHE 1.1 Beta2 release, we have implemented two API which helps synchronizing various processes. These are wincache_lock and wincache_unlock. We will see now how to solve Readers-Writers problem using these two WINCACHE API. This will help in understanding these API more in how these API can be used to solve real life problem.
Our writer actually writes a variable called RANDOM_NUMBER in WINCACHE user cache each time and uses PHP rand() function. Reader just reads this variable. So the intent is to allow multiple readers to read the variable RANDOM_NUMBER but at a time only one write can change it. And here goes the code:
<?php define('WRITE_LCK_NAME', 'writer'); define('READ_LCK_NAME' , 'reader'); function writer() { //Take the exclusive write lock. //The function will wait if the lock is already helpd by someone else. wincache_lock(WRITE_LCK_NAME); //Do the write. Let's say we are writing data $random in user cache. $random = wincache_ucache_set('RANDOM_NUMBER', rand()); $random = wincache_ucache_get('RANDOM_NUMBER'); echo "Writer writing the variable RANDON_NUMBER in shared memory to: " . $random . '<br>'; //Release the lock wincache_unlock(WRITE_LCK_NAME); } function reader() { //Take the read lock wincache_lock(READ_LCK_NAME); //Increment the reader count if (wincache_ucache_exists('READER_COUNT')) { wincache_ucache_inc('READER_COUNT'); } else { wincache_ucache_add('READER_COUNT', 1); } if (wincache_ucache_get('READER_COUNT') == 1) { //Get the write lock wincache_lock(WRITE_LCK_NAME); } //Release the read lock wincache_unlock(READ_LCK_NAME); //Do the actual reading $random = wincache_ucache_get('RANDOM_NUMBER'); echo "Reader reading the variable RANDON_NUMBER in shared memory which is: " . $random . '<br>'; //Done with reading, acquire the read lock again wincache_lock(READ_LCK_NAME); //If the reader count goes down to 0, release the write lock if (wincache_ucache_dec('READER_COUNT') == 0) { //Release the write lock wincache_unlock(WRITE_LCK_NAME); } //Release the read lock wincache_unlock(READ_LCK_NAME); } //Test this now. writer(); sleep(5); reader(); reader(); reader(); reader(); reader(); writer(); writer(); reader(); reader(); reader(); reader(); reader(); reader(); reader(); reader(); reader(); reader(); ?>
You can paste this code in a file and save it as readers_writers_solved.php and run it in multiple tabs in browser. You will see process synchronization in action here. This code is just a demonstration of lock API in WINCACHE and is provided for understanding and clarity prospect. Please test your code thoroughly to ensure that code is not initiating any kind of race condition.
For good example of real time usage of lock look at Drupal integration of WINCACHE user cache at http://drupal.org/node/743028.
Hope this was an interesting read for all of you and till we meet again ‘Good Bye’.
Thanks,
Don.
PS: To know what’s in store for WINCACHE in upcoming release and what is already done look at the post from our developer here.