5

私は pthread を学んでいて、リーダーライターロックに遭遇しました。シナリオは非常に単純です。グローバル変数がすべてのスレッドで共有されている場合、リーダーは同じグローバル変数の現在の値を出力し続け、ライターは同じ変数を更新します。2 つのミューテックス (pthread_mutex_t) を使用してこの同期を実現できますが、これと同じ結果を得るために「1 つの」リーダー/ライター ロックを使用したいと考えています。ただし、ここ (以下のプログラムの出力) に見られるように、1 つのリーダー/ライター ロックでは、リーダーは x の最初の値のみを認識し、グローバル変数への更新は認識しません。ここに光を投げてください。

コード:

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <pthread.h>
#include <poll.h>

#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))

int x = 0;

pthread_rwlock_t lock_rw = PTHREAD_RWLOCK_INITIALIZER;

void *reader_thread(void *arg)
{
    int i;
    int newx, oldx;
    newx = oldx = -1;

    pthread_rwlock_t *p = (pthread_rwlock_t *)arg;

    if (pthread_rwlock_rdlock(p) != 0) {
        perror("reader_thread: pthread_rwlock_rdlock error");
        exit(__LINE__);
    }

    for (i = 0; i < 100; i++) {
        newx = ACCESS_ONCE(x);
        if (newx != oldx) {
            printf("reader_lock: x: %d\n",x);
        }
        oldx = newx;
        poll(NULL, 0, 1);
    }

    if (pthread_rwlock_unlock(p) != 0) {
        perror("reader thread: pthred_rwlock_unlock error");
        exit(__LINE__);
    }

    return NULL;
}

void *writer_thread(void *arg)
{
    int i;
    pthread_rwlock_t *p = (pthread_rwlock_t *)arg;

    if (pthread_rwlock_wrlock(p) != 0) {
        perror("writer thread: pthread_rwlock_wrlock error");
        exit(__LINE__);
    }

    for (i = 0; i < 3; i++) {
        ACCESS_ONCE(x)++;
        poll(NULL, 0, 5);
    }

    if (pthread_rwlock_unlock(p) != 0) {
        perror("writer thread: pthread_rwlock_unlock error");
        exit(__LINE__);
    }

    return NULL;
}

int main(void)
{
    pthread_t tid1, tid2;
    void *vp;
    if (pthread_create(&tid1, NULL, reader_thread, &lock_rw) != 0) {
        perror("pthread_create error");
        exit (__LINE__);
    }

    if (pthread_create(&tid2, NULL, writer_thread, &lock_rw) != 0) {
        perror("pthread_create error");
        exit (__LINE__);
    }

    //wait for the thread to complete
    if (pthread_join(tid1, &vp) != 0) {
        perror("pthread_join error");
        exit (__LINE__);
    }

    if (pthread_join(tid2, &vp) != 0) {
        perror("pthread_join error");
        exit (__LINE__);
    }

    printf("Parent process sees x: %d\n",x);
    return 0;
}

gcc pthread_rwlock.c -o rwlock -pthread -Wall -Werror

./rwlock

リーダー_ロック: x: 0

親プロセスは x: 3 を見ます

4

1 に答える 1

7

スレッドがロックを取得すると、同じロックを取得しようとする他のスレッドは、最初のスレッドがロックを解放するまで中断されます。

ここで何が起こっているかというと、リーダー スレッドが開始し、ロックを取得して、for/pollループに入るということです。

ライター スレッドが開始し、リーダー スレッドによって既に取得されているロックを取得しようとしますが、ブロックされたままになりpthread_rwlock_wrlockます。

実際にやりたいことはlock/unlock、共有変数にアクセスするコードの前後に権利を置くことです。

thread_rwlock_rdlock(p);
newx = ACCESS_ONCE(x);
thread_rwlock_unlock(p);
...
thread_rwlock_wrlock(p);
ACCESS_ONCE(x)++;
thread_rwlock_unlock(p);
于 2013-10-20T21:04:39.320 に答える