С учетом этого примера кода:
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
void *func1(void *);
void *func2(void *);
static pthread_rwlock_t rwLock = PTHREAD_RWLOCK_INITIALIZER;
int main() {
pthread_t thread1;
pthread_t thread2;
pthread_create(&thread1, NULL, func1, NULL);
sleep(1);
int i;
for (i = 0; i < 3; i++) {
pthread_create(&thread2, NULL, func2, (void *)(i + 1));
}
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
return 0;
}
void *func1(void *arg) {
int j;
for(j = 0; j < 10; j++) {
printf("func 1: trying lock\n");
pthread_rwlock_wrlock(&rwLock);
printf("func 1: lock aquired, sleep 1 sec...\n");
sleep(1);
pthread_rwlock_unlock(&rwLock);
}
}
void *func2(void *arg) {
int true = 1;
while(true) {
pthread_rwlock_rdlock(&rwLock);
printf("func 2: thread %i: lock aquired, sleep 1 sec... \n", (int)arg);
sleep(1);
pthread_rwlock_unlock(&rwLock);
}
}
У меня есть один поток, повторяющийся в func1, в котором запрашивается блокировка записи в течение 1 секунды, и 3 других, повторяющиеся в func 2, в котором запрашивается блокировка чтения1 секунда.
На справочной странице pthread_rwlock_rdlock написано: «Вызывающий поток получает блокировку чтения, если записывающее устройство не удерживает блокировку, и нет записывающих устройств, заблокированных в блокировке.».Из моей вставки вывода в строке 5 вы можете увидеть в «func 1: пытаемся заблокировать», что писатель явно находится в блоке, так почему же мои читатели все равно получат блокировку?После строки 5 каждую секунду печатаются 3 строки.Уменьшение количества тем в моем читателе увеличивает вероятность того, что писатель получит блокировку.
func 1: trying lock
func 1: lock aquired, sleep 1 sec...
func 1: trying lock
func 1: lock aquired, sleep 1 sec...
func 1: trying lock
func 2: thread 1: lock aquired, sleep 1 sec...
func 2: thread 3: lock aquired, sleep 1 sec...
func 2: thread 2: lock aquired, sleep 1 sec...
func 2: thread 2: lock aquired, sleep 1 sec...
func 2: thread 3: lock aquired, sleep 1 sec...
func 2: thread 1: lock aquired, sleep 1 sec...
func 2: thread 2: lock aquired, sleep 1 sec...
func 2: thread 3: lock aquired, sleep 1 sec...
func 2: thread 1: lock aquired, sleep 1 sec...
func 2: thread 3: lock aquired, sleep 1 sec...
func 2: thread 1: lock aquired, sleep 1 sec...
func 2: thread 2: lock aquired, sleep 1 sec...
func 2: thread 3: lock aquired, sleep 1 sec...
func 2: thread 2: lock aquired, sleep 1 sec...
func 2: thread 1: lock aquired, sleep 1 sec...
func 2: thread 3: lock aquired, sleep 1 sec...
func 2: thread 1: lock aquired, sleep 1 sec...
func 2: thread 2: lock aquired, sleep 1 sec...
...
Добавлен еще один пример
#define _GNU_SOURCE
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#define SIZE 10000
void *writerFunc(void *);
void *readerFunc1(void *);
void *readerFunc2(void *);
int setSchedulePolicyTo2(void);
static pthread_rwlock_t rwLock = PTHREAD_RWLOCK_INITIALIZER;
int main() {
pthread_t readerThread1;
pthread_t readerThread2;
pthread_t writerThread;
pthread_create(&readerThread1, NULL, readerFunc1, NULL);
sleep(1);
pthread_create(&readerThread1, NULL, writerFunc, NULL);
sleep(1);
pthread_create(&readerThread2, NULL, readerFunc2, NULL);
pthread_join(readerThread1, NULL);
pthread_join(readerThread2, NULL);
pthread_join(writerThread, NULL);
return 0;
}
void *writerFunc(void *arg) {
printf(" writer's scheduling policy: %d\n", setSchedulePolicyTo2());
printf("writer 1: trying to acquire rw lock...(on hold)\n");
pthread_rwlock_wrlock(&rwLock); // Note ..._wrlock
printf("writer 1: rw lock acquired \n");
pthread_rwlock_unlock(&rwLock);
}
void *readerFunc1(void *arg) {
printf(" reader1's scheduling policy: %d\n", setSchedulePolicyTo2());
printf("reader 1: trying to acquire rw lock...(on hold)\n");
pthread_rwlock_rdlock(&rwLock);
printf("reader 1: rw lock acquired \n");
sleep(3); // enough time to let reader 2 to acquire rw lock before this reader releases it.
pthread_rwlock_unlock(&rwLock);
printf("reader 1: rw lock released \n");
}
void *readerFunc2(void *arg) {
printf(" reader2's scheduling policy: %d\n", setSchedulePolicyTo2());
printf("reader 2: trying to acquire rw lock...(on hold)\n");
pthread_rwlock_rdlock(&rwLock);
printf("reader 2: rw lock acquired \n");
sleep(2);
pthread_rwlock_unlock(&rwLock);
printf("reader 2: rw lock released \n");
}
int setSchedulePolicyTo2() {
struct sched_param sp;
sp.sched_priority = 10;
int policy;
int j;
if((j = pthread_setschedparam(pthread_self(), SCHED_RR, &sp)) != 0) {
printf("error: %s \n", strerror(errno));
}
if((j = pthread_getschedparam(pthread_self(), &policy, &sp)) != 0) {
printf("error: %s \n", strerror(errno));
}
return policy;
}
output:
$ gcc main.c -pthread
$ sudo ./a.out
reader1's scheduling policy: 2
reader 1: trying to acquire rw lock...(on hold)
reader 1: rw lock acquired
writer's scheduling policy: 2
writer 1: trying to acquire rw lock...(on hold)
reader2's scheduling policy: 2
reader 2: trying to acquire rw lock...(on hold)
reader 2: rw lock acquired
reader 1: rw lock released
reader 2: rw lock released
writer 1: rw lock acquired
Segmentation fault (end of program)
Согласно man-странице pthread_rwlock_rdlock, считыватель 2 должен , а не получить блокировку, потому что имеется блокировщик записи с тем же приоритетом, и политика планирования всех потоков установлена в SCHED_RR (2).
Если поддерживается параметр планирования выполнения потоков и потоки, участвующие в блокировке, выполняются с помощью политик планирования SCHED_FIFO или SCHED_RR, вызывающий поток не должен получать блокировку, если записывающее устройство удерживает блокировку или если записывающие устройства с более высоким или равным приоритетомзаблокированы на замке;в противном случае вызывающий поток должен получить блокировку.
Писатель получает блокировку только тогда, когда оба считывателя сняли блокировку rw.