linux-c-programming.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Steven" <sos22@cam.ac.uk>
To: Harmeet Uppal <Harmeet_Uppal@KeaneIndia.com>
Cc: linux-c-programming@vger.kernel.org
Subject: Re: Need to implement
Date: Wed, 10 Sep 2003 21:53:29 +0100	[thread overview]
Message-ID: <20030910205329.GA46661@archibold.chu.cam.ac.uk> (raw)
In-Reply-To: <8EA11405E59BD611BA7100104B93C260020B2777@exdel01.del.mgsl.com>

[-- Attachment #1: Type: text/plain, Size: 3689 bytes --]

> Any clues how to implement a Read-Write lock on Linux using write
> preference.
From memory, the standard implementation on top of mutexes and
condition variables goes a bit like this:

struct biassed_lock {
	mutex lock;                 /* Lock to protect the other
				       fields of this structure. */
	int num_writers_waiting;
	int num_readers_waiting;
	int num_readers_active;
	int num_writers_active;
	pthread_cond_t event_object;
};

void write_lock(struct biassed_lock *bl)
{
	lock(bl->lock);
	bl->num_writers_waiting++;
	while (bl->num_readers_active || bl->num_writers_active)
		pthread_cond_wait(bl->event_object, bl->lock);
	bl->num_writers_waiting--;
	bl->num_writers_active++;
	unlock(bl->lock);
}

void read_lock(struct biassed_lock *bl)
{
	lock(bl->lock);
	bl->num_readers_waiting++;
	while (bl->num_writers_active || bl->num_writers_waiting)
		pthread_cond_wait(bl->event_object, bl->lock);
	bl->num_readers_active++;
	bl->num_readers_waiting--;
	unlock(bl->lock);
}

void upgrade_lock(struct biassed_lock *bl)
{
	lock(bl->lock);
	bl->num_writers_waiting++;
	assert(bl->num_writers_active == 0);
	while (bl->num_readers_active > 1)
		pthread_cond_wait(bl->event_object, bl->lock);
	assert(bl->num_writers_active == 0);
	bl->num_writers_active++;
	bl->num_readers_active--;
	bl->num_readers_waiting--;
	unlock(bl->lock);
}

void write_unlock(struct biassed_lock *bl)
{
	lock(bl->lock);
	bl->num_writers_active--;
	pthread_cond_broadcast(bl->event_object);
	unlock(bl->lock);
}

void read_unlock(struct biassed_lock *bl)
{
	lock(bl->lock);
	bl->num_readers_active--;
	pthread_cond_broadcast(bl->event_object);
	unlock(bl->lock);
}

Internally, the behaviour is roughly this:

1) Unless bl->lock is held:
   a) bl->num_readers_active is the number of threads currently
   holding a read lock on bl.
   b) bl->num_readers_waiting is the number of threads currently
   waiting for a read lock on bl.
   c) bl->num_writers_active is the number of threads currently
   holding a write lock on bl (either 0 or 1).
   d) bl->num_writers_waiting is the number of threads currently
   waiting for a write lock on bl.
2) num_{readers,writers}_{active,waiting} are only ever modified with
   the lock held.
3) event_object is signalled whenever bl->num_writers_active or
   bl->num_readers_active decreases.

Externally, a biassed_lock behaves like this:

4) If a thread enters write_lock while a read lock is in place,
   it will block until the read lock is removed.
5) If a thread enters write_lock while a write lock is in place,
   it will block until the write lock is removed.
6) If a thread enters read_lock while a write lock is in place or
   while another thread is waiting for a write lock, it will
   block until those write locks have been acquired and released.
7) If a thread enters write_unlock with other threads blocked
   trying to acquire a write lock, it will unblock precisely one
   of those.  Otherwise, if there are threads trying to acquire
   a read lock, it will unblock all of those.  Otherwise, it
   just marks the lock as available.
8) If a thread enters read_unlock with other threads blocked
   trying to acquire a write lock, and it is the last thread to
   hold a read lock, it will unblock precisely one of the threads
   trying to get the write lock.
9) If a thread holds a read lock, then calling upgrade_lock(bl) is
   equivalent to calling read_unlock(bl); write_lock(bl);, except
   that it is atomic.


It's been a while since I've needed to do anything like this, though,
so test thoroughly...

Steven Smith,
sos22@cam.ac.uk.

[-- Attachment #2: Type: application/pgp-signature, Size: 187 bytes --]

      parent reply	other threads:[~2003-09-10 20:53 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2003-09-08 12:13 Need to implement Harmeet Uppal
2003-09-08 15:08 ` Mariano Moreyra
2003-09-10 20:53 ` Steven [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20030910205329.GA46661@archibold.chu.cam.ac.uk \
    --to=sos22@cam.ac.uk \
    --cc=Harmeet_Uppal@KeaneIndia.com \
    --cc=linux-c-programming@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).