Linux 读写锁

Linux读写锁比mutex有更高的适用性,可以多个线程同时占用读模式的读写锁,但是只能一个线程占用写模式的读写锁;

1,当读写锁是写加锁状态<时, 在这个锁被解锁之前, 所有试图对这个锁加锁的线程都会被阻塞.

2,当读写锁在读加锁状态时, 所有试图以读模式对它进行加锁的线程都可以得到访问权,但是以写模式对它进行枷锁的线程将阻塞;

3,当读写锁在读模式锁状态时, 如果有另外线程试图以写模式加锁,读写锁通常会阻塞随后的读模式锁请求, 这样可以避免读模式锁长期占用, 而等待的写模式锁请求长期阻塞;

这种锁适用对数据结构进行读的次数比写的次数多的情况下,因为可以进行读锁共享。

2. 适用性:

读写锁适合于对数据结构的读次数比写次数多得多的情况. 因为, 读模式锁定时可以共享, 以写模式锁住时意味着独占, 所以读写锁又叫共享-独占锁.

1)初始化和销毁

#include ;

int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

成功则返回0, 出错则返回错误编号.

2)读加锁和写加锁
获取锁的两个函数是阻塞操作

#include ;

int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

成功则返回0, 出错则返回错误编号.

3)非阻塞获得读锁和写锁
非阻塞的获取锁操作, 如果可以获取则返回0, 否则返回错误的EBUSY.

#include 

int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);

成功则返回0, 出错则返回错误编号.

example:

#include 
#include 
#include 
   
#define THREAD_NUM 3
#define JOB_NUM 10
   
struct job {
    struct job *j_next;
    struct job *j_prev;
    pthread_t j_id;  /* tells which thread handles this job */
    /* ...more stuff here... */
    int j_visited;  
    /* whether this job is done. */
};
   
struct queue {
    struct job *q_head;
    struct job *q_tail;
    pthread_rwlock_t q_lock;
};
   
static struct queue q;
/*
 * Initialize a queue.
 */
int queue(struct queue *qp)
{
    int err;
   
    qp->q_head = NULL;
    qp->q_tail = NULL;
    err = pthread_rwlock_init(&qp->q_lock, NULL);
    if (0 != err) {
        return err;
    }
   
    /* ...continue initialization... */
    return 0;
}
   
/*
 * Insert a job at the head of the queue.
 */
void job_insert(struct queue *qp, struct job *jp)
{
    pthread_rwlock_wrlock(&qp->q_lock);
    jp->j_next = qp->q_head;
    jp->j_prev = NULL;
    if (qp->q_head != NULL) {
        qp->q_head->j_prev = jp;
    } else {
        qp->q_tail = jp;  /* list was empty */
    }
    qp->q_head = jp;
    pthread_rwlock_unlock(&qp->q_lock);
}
   
/*
 * Append a job on the tail of the queue.
 */
void job_append(struct queue *qp, struct job *jp)
{
    pthread_rwlock_wrlock(&qp->q_lock);
    jp->j_next = NULL;
    jp->j_prev = qp->q_tail;
    if (qp->q_tail != NULL) {
        qp->q_tail->j_next = jp;
    } else {
        qp->q_head = jp;  /* list was empty */
    }
    qp->q_tail = jp;
    pthread_rwlock_unlock(&qp->q_lock);
}
   
/*
 * Remove the given job from a queue.
 */
void job_remove(struct queue *qp, struct job *jp)
{
    pthread_rwlock_wrlock(&qp->q_lock);
    if (jp == qp->q_head) {
        qp->q_head = qp->q_head->j_next;
        if (qp->q_tail == jp) {
            qp->q_tail = NULL; 
        }
    } else if (jp == qp->q_tail) {
        qp->q_tail = jp->j_prev;
    } else {
        jp->j_prev->j_next = jp->j_next;
        jp->j_next->j_prev = jp->j_prev;
    }
    pthread_rwlock_unlock(&qp->q_lock);
}
   
/*
 * Find a job for the given thread ID.
 */
struct job* job_find(struct queue *qp, pthread_t id) 
{
    struct job *jp;
   
    if (pthread_rwlock_rdlock(&qp->q_lock) != 0) {
        return NULL;
    }
   
    for (jp = qp->q_head; jp != NULL; jp = jp->j_next) {
        if (pthread_equal(jp->j_id, id)) {
            break;
        }
    }
    pthread_rwlock_unlock(&qp->q_lock);
    return jp;
}
   
void* thrd_func(void *arg)
{
    pthread_t tid = pthread_self(); 
    struct job *jp = NULL;
    int donenum = 0;
    while (donenum < JOB_NUM) {
        jp = job_find(&q, tid);
        if (NULL != jp) {
            jp->j_visited = 1;
            donenum++;
            job_remove(&q, jp);
        }
    }
    return NULL;
}
   
int main()
{
    pthread_t tids[THREAD_NUM];
    int err,i,j,k;
    void *tret = NULL;
    struct job *pjob = NULL;
    err = i = j = k = 0;
    pjob = (struct job*)malloc(sizeof(struct job) * THREAD_NUM * JOB_NUM);
    if (NULL == pjob) {
        printf("malloc failed\n");
        return -1;
    }
    for (i = 0; i < THREAD_NUM;i++) {
        err = pthread_create(&tids[i], NULL, thrd_func, (void*)i);    
        if (0 != err) {
            printf("pthread_create failed\n");
            return -1;
        }
        for (j = 0; j < JOB_NUM;j++) {
            k = j + i * JOB_NUM;
            pjob[k].j_id = tids[i];
            pjob[k].j_visited = 0;
            job_insert(&q, &pjob[k]);
        }
    }
   
    for ( i = 0; i < THREAD_NUM;i++) {
        err = pthread_join(tids[i], &tret);
        if (0 != err) {
            printf("pthread_join failed\n");
            return -1;
        }
    }
    for (i = 0; i < THREAD_NUM;i++) 
        for (j = 0; j < JOB_NUM;j++) {
            k = j + i * JOB_NUM;
            printf("id : %d, visited : %d\n", (int)pjob[k].j_id, pjob[k].j_visited);
        }
    if (NULL != pjob) {
        free(pjob);
    }
    return 0;
}

标签:none