Sun Microsystems, Inc.
spacerspacer
spacer www.sun.com docs.sun.com |
spacer
black dot
 
 
4.  Programming with Synchronization Objects Using Read-Write Locks Read Lock on Read-Write Lock pthread_rwlock_rdlock(3THR)  Previous   Contents   Next 
   
 

Return Value

If successful, pthread_rwlock_rdlock() returns zero. Otherwise, an error number is returned to indicate the error.

 

EINVAL

The value specified by attr or rwlock is invalid.

Read Lock With a Nonblocking Read-Write Lock

pthread_rwlock_tryrdlock(3THR)

#include <pthread.h>

int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);

pthread_rwlock_tryrdlock(3THR) applies a read lock as in pthread_rwlock_rdlock() with the exception that the function fails if any thread holds a write lock on rwlock or there are writers blocked on rwlock. (For Solaris threads, see "rw_tryrdlock(3THR)".)

Return Value

pthread_rwlock_tryrdlock() returns zero if the lock for reading on the read-write lock object referenced by rwlock is acquired. Otherwise an error number is returned to indicate the error.

 

EBUSY

The read-write lock could not be acquired for reading because a writer holds the lock or was blocked on it.

Write Lock on Read-Write Lock

pthread_rwlock_wrlock(3THR)

#include <pthread.h>

int  pthread_rwlock_wrlock(pthread_rwlock_t *rwlock );

pthread_rwlock_wrlock(3THR) applies a write lock to the read-write lock referenced by rwlock. The calling thread acquires the write lock if no other thread (reader or writer) holds the read-write lock rwlock. Otherwise, the thread blocks (that is, does not return from the pthread_rwlock_wrlock() call) until it can acquire the lock. Results are undefined if the calling thread holds the read-write lock (whether a read or write lock) at the time the call is made.

Implementations are allowed to favor writers over readers to avoid writer starvation. (For instance, the Solaris threads implementation favors writers over readers. See "rw_wrlock(3THR)".)

Results are undefined if pthread_rwlock_wrlock() is called with an uninitialized read-write lock.

If a signal is delivered to a thread waiting for a read-write lock for writing, upon return from the signal handler the thread resumes waiting for the read-write lock for writing as if it was not interrupted.

Return Value

pthread_rwlock_rwlock() returns zero if the lock for writing on the read-write lock object referenced by rwlock is acquired. Otherwise an error number is returned to indicate the error.

Write Lock With a Nonblocking Read-Write Lock

pthread_rwlock_trywrlock(3THR)

#include <pthread.h>

int pthread_rwlock_trywrlock(pthread_rwlock_t  *rwlock);

pthread_rwlock_trywrlock(3THR) applies a write lock like pthread_rwlock_wrlock(), with the exception that the function fails if any thread currently holds rwlock (for reading or writing). (For Solaris threads, see "rw_trywrlock(3THR)".)

Results are undefined if pthread_rwlock_trywrlock() is called with an uninitialized read-write lock.

If a signal is delivered to a thread waiting for a read-write lock for writing, on return from the signal handler the thread resumes waiting for the read-write lock for writing as if it was not interrupted.

Return Value

If successful, pthread_rwlock_trywrlock() returns zero if the lock for writing on the read-write lock object referenced by rwlock is acquired. Otherwise, an error number is returned to indicate the error.

 

EBUSY

The read-write lock could not be acquired for writing because it is already locked for reading or writing.

Unlock a Read-Write Lock

pthread_rwlock_unlock(3THR)

#include <pthread.h>

pthread_rwlock_unlock(3THR) releases a lock held on the read-write lock object referenced by rwlock. Results are undefined if the read-write lock rwlock is not held by the calling thread. (For Solaris threads, see "rw_unlock(3THR)".)

If pthread_rwlock_unlock() is called to release a read lock from the read-write lock object and there are other read locks currently held on this read-write lock object, the read-write lock object remains in the read locked state. If pthread_rwlock_unlock() releases the calling thread's last read lock on this read-write lock object, then the calling thread is no longer one of the owners of the object. If pthread_rwlock_unlock() releases the last read lock for this read-write lock object, the read-write lock object will be put in the unlocked state with no owners.

If pthread_rwlock_unlock() is called to release a write lock for this read-write lock object, the read-write lock object will be put in the unlocked state with no owners.

If the call to the pthread_rwlock_unlock() results in the read-write lock object becoming unlocked and there are multiple threads waiting to acquire the read-write lock object for writing, the scheduling policy is used to determine which thread acquires the read-write lock object for writing. If there are multiple threads waiting to acquire the read-write lock object for reading, the scheduling policy is used to determine the order in which the waiting threads acquire the read-write lock object for reading. If there are multiple threads blocked on rwlock for both read locks and write locks, it is unspecified whether the readers acquire the lock first or whether a writer acquires the lock first.

Results are undefined if pthread_rwlock_unlock() is called with an uninitialized read-write lock.

Return Value

If successful, pthread_rwlock_unlock() returns zero. Otherwise, an error number is returned to indicate the error.

Destroy a Read-Write Lock

pthread_rwlock_destroy(3THR)

#include <pthread.h>

int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

pthread_rwlock_t  rwlock = PTHREAD_RWLOCK_INITIALIZER;

pthread_rwlock_destroy(3THR) destroys the read-write lock object referenced by rwlock and releases any resources used by the lock. The effect of subsequent use of the lock is undefined until the lock is re-initialized by another call to pthread_rwlock_init() An implementation can cause pthread_rwlock_destroy() to set the object referenced by rwlock to an invalid value. Results are undefined if pthread_rwlock_destroy() is called when any thread holds rwlock. Attempting to destroy an uninitialized read-write lock results in undefined behavior. A destroyed read-write lock object can be re-initialized using pthread_rwlock_init(); the results of otherwise referencing the read-write lock object after it has been destroyed are undefined. (For Solaris threads, see "rwlock_destroy(3THR)".)

Return Value

If successful, pthread_rwlock_destroy() returns zero. Otherwise, an error number is returned to indicate the error.

 

EINVAL

The value specified by attr or rwlock is invalid.

Synchronization Across Process Boundaries

Each of the synchronization primitives can be set up to be used across process boundaries. This is done quite simply by ensuring that the synchronization variable is located in a shared memory segment and by calling the appropriate init() routine, after the primitive has been initialized with its shared attribute set as interprocess.

Producer/Consumer Problem Example

Example 4-17 shows the producer/consumer problem with the producer and consumer in separate processes. The main routine maps zero-filled memory (that it shares with its child process) into its address space.

A child process is created that runs the consumer. The parent runs the producer.

This example also shows the drivers for the producer and consumer. The producer_driver() simply reads characters from stdin and calls producer(). The consumer_driver() gets characters by calling consumer() and writes them to stdout.

The data structure for Example 4-17 is the same as that used for the condition variables example (see Example 4-4). Two semaphores represent the number of full and empty buffers and ensure that producers wait until there are empty buffers and that consumers wait until there are full buffers.


Example 4-17 Synchronization Across Process Boundaries

main() {
    int zfd;
    buffer_t *buffer;
    pthread_mutexattr_t mattr;
    pthread_condattr_t cvattr_less, cvattr_more;

    zfd = open("/dev/zero", O_RDWR);
    buffer = (buffer_t *)mmap(NULL, sizeof(buffer_t),
        PROT_READ|PROT_WRITE, MAP_SHARED, zfd, 0);
    buffer->occupied = buffer->nextin = buffer->nextout = 0;

    pthread_mutex_attr_init(&mattr);
    pthread_mutexattr_setpshared(&mattr,
        PTHREAD_PROCESS_SHARED);

    pthread_mutex_init(&buffer->lock, &mattr);
    pthread_condattr_init(&cvattr_less);
    pthread_condattr_setpshared(&cvattr_less, PTHREAD_PROCESS_SHARED);
    pthread_cond_init(&buffer->less, &cvattr_less);
    pthread_condattr_init(&cvattr_more);
    pthread_condattr_setpshared(&cvattr_more,   
        PTHREAD_PROCESS_SHARED);
    pthread_cond_init(&buffer->more, &cvattr_more);

    if (fork() == 0)
        consumer_driver(buffer);
    else
        producer_driver(buffer);
}

void producer_driver(buffer_t *b) {
    int item;

    while (1) {
        item = getchar();
        if (item == EOF) {
            producer(b, `\0');
            break;
        } else
            producer(b, (char)item);
    }
}

void consumer_driver(buffer_t *b) {
    char item;

    while (1) {
        if ((item = consumer(b)) == '\0')
            break;
        putchar(item);
    }
}

 
 
 
  Previous   Contents   Next