Читаем Programming with POSIX® Threads полностью

We keep track of a boolean variable for "writer active," since there can only be one. There are also counters for "readers active," "readers waiting," and "writers waiting." We could get by without counters for readers and writers waiting. All readers are awakened simultaneously using a broadcast, so it doesn't matter how many there are. Writers are awakened only if there are no readers, so we could dispense with keeping track of whether there are any threads waiting to write (at the cost of an occasional wasted condition variable signal when there are no waiters).

We count the number of threads waiting for read access because the condition variable waits might be canceled. Without cancellation, we could use a simple flag — "threads are waiting for read" or "no threads are waiting for read." Each thread could set it before waiting, and we could clear it before broadcasting to wake all waiting readers. However, because we can't count the threads waiting on a condition variable, we wouldn't know whether to clear that flag when a waiting reader was canceled. This information is critical, because if there are no readers waiting when the read/write lock is unlocked, we must wake a writer — but we cannot wake a writer if there are waiting readers. A count of waiting readers, which we can decrease when a waiter is canceled, solves the problem.

The consequences of "getting it wrong" are less important for writers than for readers. Because we check for readers first, we don't really need to know whether there are writers. We could signal a "potential writer" anytime the read/write lock was released with no waiting readers. But counting waiting writers allows us to avoid a condition variable signal when no threads are waiting.

Part 2 shows the rest of the definitions and the function prototypes.

4-6 The RWLOCK_INITIALlZER macro allows you to statically initialize a read/write lock.

11-18 Of course, you must also be able to initialize a read/write lock that you cannot allocate statically, so we provide rwl_init to initialize dynamically, and rwl_ destroy to destroy a read/write lock once you're done with it. In addition, there are functions to lock and unlock the read/write lock for either read or write access. You can "try to lock" a read/write lock, either for read or write access, by calling rwl_readtrylock or rwl_writetrylock., just as you can try to lock a mutex by calling pthread_mutex_trylock.

■ rwlock.h part 2 interfaces

1 /*

2 * Support static initialization of barriers.

3 */

4 #define RWL_INITIALIZER \

5 {PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, \

6 PTHREAD_COND_INITIALIZER, RWLOCK_VALID, 0, 0, 0, 0}

7

8 /*

9 * Define read/write lock functions.

10 */

11 extern int rwl_init (rwlock_t *rwlock);

12 extern int rwl_destroy (rwlock_t *rwlock);

13 extern int rwl_readlock (rwlock_t *rwlock);

14 extern int rwl_readtrylock (rwlock_t *rwlock);

15 extern int rwl_readunlock (rwlock_t *rwlock);

16 extern int rwl_writelock (rwlock_t *rwlock);

17 extern int rwl_writetrylock (rwlock_t *rwlock);

18 extern int rwl_writeunlock (rwlock_t *rwlock);

The file rwlock.c contains the implementation of read/write locks. The following examples break down each of the functions used to implement the rwlock.h interfaces.

Part 1 shows rwl_init, which initializes a read/write lock. It initializes the Pthreads synchronization objects, initializes the counters and flags, and finally sets the valid sentinel to make the read/write lock recognizable to the other interfaces. If we are unable to initialize the read condition variable, we destroy the mutex that we'd already created. Similarly, if we are unable to initialize the write condition variable, we destroy both the mutex and the read condition variable.

■ rwlock.c part 1 rwl_init

1 #include

2 #include "errors.h"

3 #include "rwlock.h"

4

5 /*

6 * Initialize a read/write lock.

7 */

8 int rwl_init (rwlock_t *rwl)

9 {

10 int status;

11

12 rwl->r_active = 0;

13 rwl->r_wait = rwl->w_wait = 0;

14 rwl->w_active = 0;

15 status = pthread_mutex_init (&rwl->mutex, NULL);

16 if (status != 0)

Перейти на страницу:

Похожие книги

C++: базовый курс
C++: базовый курс

В этой книге описаны все основные средства языка С++ - от элементарных понятий до супервозможностей. После рассмотрения основ программирования на C++ (переменных, операторов, инструкций управления, функций, классов и объектов) читатель освоит такие более сложные средства языка, как механизм обработки исключительных ситуаций (исключений), шаблоны, пространства имен, динамическая идентификация типов, стандартная библиотека шаблонов (STL), а также познакомится с расширенным набором ключевых слов, используемым в .NET-программировании. Автор справочника - общепризнанный авторитет в области программирования на языках C и C++, Java и C# - включил в текст своей книги и советы программистам, которые позволят повысить эффективность их работы. Книга рассчитана на широкий круг читателей, желающих изучить язык программирования С++.

Герберт Шилдт

Программирование, программы, базы данных
Delphi. Трюки и эффекты
Delphi. Трюки и эффекты

«Delphi. Трюки и эффекты», как и все издания данной серии, адресована тем, кто хочет научиться делать с помощью уже знакомых программных пакетов новые, интересные вещи. В первой части книги многое говорится о среде разработки Delphi (самых последних версий) и программировании на языке Object Pascal. Благодаря этому издание подходит и новичкам, и начинающим программистам. Вторая (основная) часть книги описывает удивительные возможности, скрытые в языке, и на примерах учит читателя программистским фокусам – от «мышек-невидимок» и «непослушных окон» до воспроизведения МРЗ и управления офисными программами Word и Excel из приложений Delphi. Купив эту книгу, вы пройдете непростой путь к вершинам программистского мастерства весело и интересно.

Валерий Викторович Борисок , Юрий Иванович Корвель , Александр Анатольевич Чиртик

Программирование, программы, базы данных