pthread_rwlock

9 views
Skip to first unread message

jeeva

unread,
Jul 2, 2002, 2:52:38 PM7/2/02
to
HI!

Does red hat Linux (7.1+) support read/write lock, preferably
pthread_rwlock?

I believe rwlock can be implemented using mutex and condition variable, Is
there any open source code available (for Linux and Solaris)

Thanks

Jeeva.


Sean P. Burke

unread,
Jul 4, 2002, 2:39:00 PM7/4/02
to

"jeeva" <som...@somewhere.com> writes:

It's fairly simple to do. Here's my implementation,
which works on any basically-functional pthread
implementation.

-SEan

/****************************************************************************
*
* File: pth_rwlock.h
*
* PURPOSE
*
* This package implements a readers/writer lock facility, using the POSIX
* threads package. This is very similar to readers/writer lock facility
* that is part of Solaris native threads, so do 'man rwlock_init' for a
* description. I have tried to name calls similarly, adding a "pth_" prefix
* to indicate that this is associated with, but not part of, the POSIX thread
* package.
*
* This package does not prevent a thread from acquiring the read lock twice,
* such as when a function in your package that holds the lock calls another
* function which tries to acquire the lock. It is important to ensure that
* your application does not do this, as a deadlock can result.
*
* It happens in this way: a thread first takes a read lock, and subsequently
* another thread attempts to acquire a write lock. The writer must wait for
* all readers to yield the lock before proceeding. When the reader tries to
* acquire the read lock again, it notices that a writer is pending, and waits
* to let the write occur. Since it is holding a read lock already, the write
* cannot proceed, and the threads deadlock.
*
* Therefore, you can recognize the deadlock in this way: there are one or
* more active readers, pending readers and pending writers, and the total
* will be more than the number of threads that share the data structure.
*
*****************************************************************************
*/
#ifndef PTH_RWLOCK_H
#define PTH_RWLOCK_H

#ifdef _REENTRANT
#include <pthread.h>
#endif

typedef struct pth_rwlock
{
int active_readers; /* -1 when writer active */
int pending_readers;
int pending_writers;
#ifdef _REENTRANT
pthread_mutex_t mutex;
pthread_cond_t ok_to_read;
pthread_cond_t ok_to_write;
#endif
} pth_rwlock_t;


/* Initialize a readers/writer lock.
*/
void pth_rwlock_init(pth_rwlock_t * lock);


/* Destroy a readers/writer lock. The space used by the rwlock is not freed.
*/
void pth_rwlock_destroy(pth_rwlock_t * lock);


/* Acquire a read-only lock.
*/
void pth_rw_rdlock(pth_rwlock_t *lock);


/* Release a read-only lock.
*/
void pth_rw_rdunlock(pth_rwlock_t * lock);


/* Acquire a write lock.
*/
void pth_rw_wrlock(pth_rwlock_t * lock);


/* Try to get a write lock, without waiting.
* As with pthread_mutex_trylock(), returns 0 on success.
*/
int pth_rw_wrtrylock(pth_rwlock_t * lock);


/* pth_rw_tryupgrade
*
* Try to upgrade a read lock to a write lock.
* Returns 0 on success, and -1 if there are other active readers.
*/
int pth_rw_tryupgrade(pth_rwlock_t * lock);


/* Release a write lock.
*/
void pth_rw_wrunlock(pth_rwlock_t * lock);


/* Release a read-only or write lock.
*/
void pth_rw_unlock(pth_rwlock_t * lock);

/*
* Some useful macros to put in assert()s.
*/
#define READ_LOCK_HELD(lock) (lock.active_readers > 0)

#define WRITE_LOCK_HELD(lock) (lock.active_readers == -1)

#endif


/****************************************************************************
*
* File: rwlock.c
*
*****************************************************************************
*/

#include <assert.h>


/* pth_rwlock_init - Initialize a readers/writer lock.
*/
void pth_rwlock_init(pth_rwlock_t * lock)
{
lock->active_readers = 0;
lock->pending_readers = 0;
lock->pending_writers = 0;
#ifdef _REENTRANT
pthread_mutex_init(&lock->mutex, PTHREAD_MUTEXATTR_DEFAULT);
pthread_cond_init (&lock->ok_to_read, PTHREAD_CONDATTR_DEFAULT);
pthread_cond_init (&lock->ok_to_write, PTHREAD_CONDATTR_DEFAULT);
#endif
}

/* pth_rwlock_destroy - Destroy a readers/writer lock.
* The space used by the rwlock is not freed.
*/
void pth_rwlock_destroy(pth_rwlock_t * lock)
{
#ifdef _REENTRANT
pthread_mutex_destroy(&lock->mutex);
pthread_cond_destroy (&lock->ok_to_read);
pthread_cond_destroy (&lock->ok_to_write);
#endif
}

/* pth_rw_rdlock - Acquire a read-only lock.
*/
void pth_rw_rdlock(pth_rwlock_t *lock)
{
#ifdef _REENTRANT
pthread_mutex_lock(&lock->mutex);

lock->pending_readers++;

/* Don't wait for pending writers - this can starve writers
* but it avoids deadlocks when readers take the lock recursively.
*
* if (lock->pending_writers > 0)
* pthread_cond_wait(&lock->ok_to_read, &lock->mutex);
*/

/* Wait while writers are active */
while (lock->active_readers < 0)
pthread_cond_wait(&lock->ok_to_read, &lock->mutex);

lock->pending_readers--;
#endif
lock->active_readers++;

#ifdef _REENTRANT
pthread_mutex_unlock(&lock->mutex);
#endif
}

/* pth_rw_rdunlock - Release a read-only lock.
*/
void pth_rw_rdunlock(pth_rwlock_t * lock)
{
#ifdef _REENTRANT
pthread_mutex_lock(&lock->mutex);
#endif
assert(lock->active_readers > 0);

lock->active_readers--;

#ifdef _REENTRANT
/* If we are the last reader out, signal writer.
*/
if (lock->active_readers == 0)
pthread_cond_signal(&lock->ok_to_write);

pthread_mutex_unlock(&lock->mutex);
#endif
}

/* pth_rw_wrlock - Acquire a write lock.
*/
void pth_rw_wrlock(pth_rwlock_t * lock)
{
#ifdef _REENTRANT
pthread_mutex_lock(&lock->mutex);

lock->pending_writers++;

while (lock->active_readers)
pthread_cond_wait(&lock->ok_to_write, &lock->mutex);

lock->pending_writers--;
#endif
assert(lock->active_readers == 0);

lock->active_readers = -1;

#ifdef _REENTRANT
pthread_mutex_unlock(&lock->mutex);
#endif
}


/* pth_rw_wrtrylock
*
* Attempt to immediately acquire a write lock. To make this
* consistent with the pthread calls, we return 0 on success,
* and -1 if the lock is busy.
*/
int pth_rw_wrtrylock(pth_rwlock_t * lock)
{
int result = -1;

#ifdef _REENTRANT
pthread_mutex_lock(&lock->mutex);
#endif

if (lock->active_readers == 0)
{
lock->active_readers = -1;
result = 0;
}

#ifdef _REENTRANT
pthread_mutex_unlock(&lock->mutex);
#endif

return result;
}


/* pth_rw_tryupgrade
*
* Attempt to immediately acquire a write lock when you already
* hold a read lock. This call will fail if there are other active
* readers. If this call succeeds, you must call pth_rw_wrunlock
* to yield the lock.
*
* To make this consistent with the pthread calls, we return 0 on
* success, and -1 if the lock is busy.
*/
int pth_rw_tryupgrade(pth_rwlock_t * lock)
{
int result = -1;

#ifdef _REENTRANT
pthread_mutex_lock(&lock->mutex);
#endif

assert(lock->active_readers > 0); /* caller at least must hold read lock */

if (lock->active_readers == 1)
{
lock->active_readers = -1;
result = 0;
}

#ifdef _REENTRANT
pthread_mutex_unlock(&lock->mutex);
#endif

return result;
}


/* pth_rw_wrunlock - Release a write lock.
*/
void pth_rw_wrunlock(pth_rwlock_t * lock)
{
#ifdef _REENTRANT
pthread_mutex_lock(&lock->mutex);
#endif

assert(lock->active_readers == -1);

lock->active_readers = 0;

#ifdef _REENTRANT
/* Signal waiters while holding the mutex, to meet the
* requirements of our pthread_cond_wait emulation for WIN32.
*/
if (lock->pending_readers != 0)
/* Wake all readers.
*/
pthread_cond_broadcast(&lock->ok_to_read);
else
/* Wake a single writer.
*/
pthread_cond_signal(&lock->ok_to_write);

pthread_mutex_unlock(&lock->mutex);
#endif
}

/* pth_rw_unlock - Promiscuous lock-release.
*/
void pth_rw_unlock(pth_rwlock_t * lock)
{
#ifdef _REENTRANT
pthread_mutex_lock(&lock->mutex);
#endif

assert(lock->active_readers != 0);
assert(lock->active_readers > -1);

if (lock->active_readers > 0)
{
lock->active_readers--;

#ifdef _REENTRANT
/* If we are the last reader out, signal writer.
*/
if (lock->active_readers == 0)
pthread_cond_signal(&lock->ok_to_write);
#endif
}
else if (lock->active_readers == -1);
{
lock->active_readers = 0;

#ifdef _REENTRANT
/* Signal waiters while holding the mutex, to meet the
* requirements of our pthread_cond_wait emulation for WIN32.
*/
if (lock->pending_readers != 0)
/* Wake all readers.
*/
pthread_cond_broadcast(&lock->ok_to_read);
else
/* Wake a single writer.
*/
pthread_cond_signal(&lock->ok_to_write);
#endif
}

#ifdef _REENTRANT
pthread_mutex_unlock(&lock->mutex);
#endif
}

Reply all
Reply to author
Forward
0 new messages