/* lock_count < 0 .. Удерживается записывающим потоком. */ /* lock_count > 0 .. Удерживается lock_count считывающими * потоками. */

/* lock_count = 0 .. Ничем не удерживается. */ int waiting_writers; /* Счетчик ожидающих записывающих

* потоков. */

} rwlock;

void

waiting_reader_cleanup (void, *arg) {

rwlock *1;

1 = (rwlock *) arg;

pthread_mutex_unlock (&l->lock);

}

void

lock_for_read (rwlock *1) {

pthread_mutex_lock (&l->lock);

pthread_cleanup_push (waiting_reader_cleanup, 1) ;

while ((l->lock_count < 0) && (l->waiting_writers ! = 0))

pthread_cond_wait (&l->rcond, &l->lock);

l->lock_count++;

/*

* Обратите внимание на то, что функция pthread_cleanup_pop()

* выполняет здесь фyнкциюwaiting_reader_cleanup(). */

pthread_cleanup_pop(l); }

void

release_read_lock (rwlock *1) {

pthread_mutex_lock (&l->lock); if (--l->lock_count == 0) pthread_cond_signal (&l- >wcond); pthread_mutex_unlock (1);

void

waiting_writer_cleanup (void *arg) {

rwlock *1;

1 = (rwlock *) arg;

if ((—l->waiting_writers == О) && (l->lock_count >= 0)) { /*

* Это происходит только в случае отмены потока. */

pthread_cond_broadcast (&l->wcond);

}

pthread_mutex_unlock (&l->lock);

}

void

lock_for_write (rwlock *1) {

pthread_mutex_lock (&l->lock),-l->waiting_writers++;

pthread_cleanup_push (waiting_writer_cleanup, 1); while (l->lock_count ! = О) pthread_cond_wait (&l->wcond, &l->lock); l->lock_count = -1; /*

* Обратите внимание на то, что функция pthread_cleanup_pop()

* выполняет здесь функцию waiting_writer_cleanup(). */

pthread_cleanup_pop (1);

}

void

release_write_lock (rwlock *1) {

pthread_mutex_lock (&l->lock);

l->lock_count = 0;

if (l->waiting_writers == О)

pthread_cond_broadcast (&l->rcond)

else

pthread_cond_signal (&l->wcond); pthread_mutex_unlock (&l->lock);

}

/*

* Эта функция вызывается для инициализации блокировки

* чтения-записи. */

void

initialize_rwlock (rwlock *1) {

pthread_mutex_init (&l->lock, pthread_mutexattr_default); pthread_cond_init (&l- >wcond, pthread_condattr_default); pthread_cond_init (&l->rcond, pthread_condattr_default); l- >lock_count = О; l->waiting_writers = О;

Приложение Б 559

}

reader_thread() {

lock_for_read (&lock);

pthread_cleanup_push (release_read_lock, &lock); /*

* Поток устанавливает блокировку для чтения. */

pthread_cleanup_pop (1);

}

writer_thread() {

lock_for_write (&lock);

pthread_cleanup_push (release_write_lock, &lock); /*

* Поток устанавливает блокировку для записи. */

pthread_cleanup_pop (1) ;

}

Замечания по использованию

Две описываемые здесь функции, pthread_cleanup_push() и pthread_cleanup_pop (), которые помещают и извлекают из стека обработчики запроса на отмену потока, можно сравнить с левой и правой круглыми скобками. Их нужно всегда использовать «в паре».

Логическое обоснование

Ограничение, налагае м ое на две функции, pthread_cleanup_push() и pthread_cleanup_pop(), которые помещают и извлекают из стека обработчики запроса на отмену потока, и состоящее в том, что они должны использоваться попарно в пределах одного и того же лексического контекста, позволяет создавать эффективные макросы (или компиляторные реализации) и эффективно управлять памятью. Вариант реализации этих функций в виде макросов может выглядеть следующим образом,

#define pthread_cleanup_push (rtn, arg) {

struct _pthread_handler_rec _cleanup_handler, **_head;

_cleanup_handler.rtn = rtn;

_cleanup_handler.arg = arg;

(void) pthread_getspecific (_pthread_handler_key, &_head);

_cleanup_handler.next = *_head;

*_head = &_cleanup_handler;

#define pthread_cleanup_pop (ex)

*_head = _cleanup_handler.next;

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату