經典的讀者寫者問題

<span style="font-size:14px;">/*
 * read_write_lock.h
 *
 *  Created on: July 29, 2016  09:55:16
 *      Author: [email protected]
 */

#ifndef __READ_WRITE_LOCK_H__
#define __READ_WRITE_LOCK_H__
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

#include <stdint.h>
#include <pthread.h>
#include <emmintrin.h>


/******************************************************************************/
enum read_write_priority_mode_e
{
    RD_PRI_MODE = 0,
    WR_PRI_MODE,
};

/******************************************************************************/
struct read_write_lock_s;
typedef void (*read_write_lock_r_lock_func)(struct read_write_lock_s *);
typedef void (*read_write_lock_r_unlock_func)(struct read_write_lock_s *);
typedef void (*read_write_lock_w_lock_func)(struct read_write_lock_s *);
typedef void (*read_write_lock_w_unlock_func)(struct read_write_lock_s *);

/******************************************************************************/
typedef struct read_write_lock_s
{
    uint32_t priority_mode;

    uint32_t reader_cnt;
    pthread_mutex_t reader_cnt_mutex;

    uint32_t writer_cnt;
    pthread_mutex_t writer_cnt_mutex;

    pthread_mutex_t reader_writer_writer_mutex;     /**< 讀寫互斥, 寫寫互斥 */

    pthread_mutex_t first_reader_mutex;
    pthread_mutex_t wait_reader_mutex;

    read_write_lock_r_lock_func rwl_read_lock;
    read_write_lock_r_unlock_func rwl_read_unlock;
    read_write_lock_w_lock_func rwl_write_lock;
    read_write_lock_w_unlock_func rwl_write_unlock;
}read_write_lock_t;

/******************************************************************************/
/*
 * 讀者優先: 根據讀寫問題的基本特性: 讀讀同步, 讀寫互斥, 寫寫互斥,
 * 必須待所有讀者完成讀取後, 寫者纔可進行寫入, 極端情況存在寫者飢餓現象
 */
/******************************************************************************/
static inline void
read_write_lock_r_lock_read_first(read_write_lock_t *rwl)
{
    pthread_mutex_lock(&rwl->reader_cnt_mutex);
    if (rwl->reader_cnt++ == 0)
        pthread_mutex_lock(&rwl->reader_writer_writer_mutex);
    pthread_mutex_unlock(&rwl->reader_cnt_mutex);
}

/******************************************************************************/
static inline void
read_write_lock_r_unlock_read_first(read_write_lock_t *rwl)
{
    pthread_mutex_lock(&rwl->reader_cnt_mutex);
    if (--rwl->reader_cnt == 0)
        pthread_mutex_unlock(&rwl->reader_writer_writer_mutex);
    pthread_mutex_unlock(&rwl->reader_cnt_mutex);
}

/******************************************************************************/
static inline void
read_write_lock_w_lock_read_first(read_write_lock_t *rwl)
{
    pthread_mutex_lock(&rwl->reader_writer_writer_mutex);
}

/******************************************************************************/
static inline void
read_write_lock_w_unlock_read_first(read_write_lock_t *rwl)
{
    pthread_mutex_unlock(&rwl->reader_writer_writer_mutex);
}

/*
 * 寫者優先: 根據讀寫問題的基本特性: 讀讀同步, 讀寫互斥, 寫寫互斥,
 * 且避免"讀者問題帶來可能的飢餓情況, 考慮這樣的情況: 存在多個讀者工作的同時, 有
 * 新的寫者進入等待, 則讓當前進行的讀者讀完後讓寫者插隊進入寫操作, 第二個讀者暫
 * 時進入等待狀態, 待寫者完成時方可進行讀取;
 */
/******************************************************************************/
static inline void
read_write_lock_r_lock_write_first(read_write_lock_t *rwl)
{
    pthread_mutex_lock(&rwl->wait_reader_mutex);
    pthread_mutex_lock(&rwl->first_reader_mutex);

    pthread_mutex_lock(&rwl->reader_cnt_mutex);
    if (++rwl->reader_cnt == 1)
        pthread_mutex_lock(&rwl->reader_writer_writer_mutex);
    pthread_mutex_unlock(&rwl->reader_cnt_mutex);

    pthread_mutex_unlock(&rwl->first_reader_mutex);
    pthread_mutex_unlock(&rwl->wait_reader_mutex);
}
static inline void
read_write_lock_r_unlock_write_first(read_write_lock_t *rwl)
{
    pthread_mutex_lock(&rwl->reader_cnt_mutex);
    if (--rwl->reader_cnt == 0)
        pthread_mutex_unlock(&rwl->reader_writer_writer_mutex);
    pthread_mutex_unlock(&rwl->reader_cnt_mutex);
}

static inline void
read_write_lock_w_lock_write_first(read_write_lock_t *rwl)
{
    pthread_mutex_lock(&rwl->writer_cnt_mutex);
    if (++rwl->writer_cnt == 1)
        pthread_mutex_lock(&rwl->first_reader_mutex);
    pthread_mutex_unlock(&rwl->writer_cnt_mutex);
    pthread_mutex_lock(&rwl->reader_writer_writer_mutex);
}
static inline void
read_write_lock_w_unlock_write_first(read_write_lock_t *rwl)
{
    pthread_mutex_unlock(&rwl->reader_writer_writer_mutex);
    pthread_mutex_lock(&rwl->writer_cnt_mutex);
    if (--rwl->writer_cnt == 0)
        pthread_mutex_unlock(&rwl->first_reader_mutex);
    pthread_mutex_unlock(&rwl->writer_cnt_mutex);
}

/******************************************************************************/
/******************************************************************************/
static inline void
read_write_lock_init(read_write_lock_t *rwl,
    enum read_write_priority_mode_e mode)
{
    int ret = 0;
    rwl->priority_mode = mode;

    switch (mode)
    {
        case RD_PRI_MODE:
        {
            pthread_mutex_init(&rwl->reader_cnt_mutex, NULL);
            rwl->reader_cnt = 0;
            pthread_mutex_init(&rwl->reader_writer_writer_mutex, NULL);
            rwl->rwl_read_lock = read_write_lock_r_lock_read_first;
            rwl->rwl_read_unlock = read_write_lock_r_unlock_read_first;
            rwl->rwl_write_lock = read_write_lock_w_lock_read_first;
            rwl->rwl_write_unlock = read_write_lock_w_unlock_read_first;
        }
        break;
        case WR_PRI_MODE:
        {
            pthread_mutex_init(&rwl->writer_cnt_mutex, NULL);
            rwl->writer_cnt = 0;
            pthread_mutex_init(&rwl->reader_writer_writer_mutex, NULL);

            pthread_mutex_init(&rwl->reader_cnt_mutex, NULL);
            rwl->reader_cnt = 0;
            pthread_mutex_init(&rwl->first_reader_mutex, NULL);
            pthread_mutex_init(&rwl->wait_reader_mutex, NULL);
            rwl->rwl_read_lock = read_write_lock_r_lock_write_first;
            rwl->rwl_read_unlock = read_write_lock_r_unlock_write_first;
            rwl->rwl_write_lock = read_write_lock_w_lock_write_first;
            rwl->rwl_write_unlock = read_write_lock_w_unlock_write_first;
        }
        break;
        default:
            break;
    }
}

/******************************************************************************/
static inline void
read_lock_r_lock(read_write_lock_t *rwl)
{
    rwl->rwl_read_lock(rwl);
}

/******************************************************************************/
static inline void
read_lock_r_unlock(read_write_lock_t *rwl)
{
    rwl->rwl_read_unlock(rwl);
}

static inline void
read_lock_w_lock(read_write_lock_t *rwl)
{
    rwl->rwl_write_lock(rwl);
}

static inline void
read_lock_w_unlock(read_write_lock_t *rwl)
{
    rwl->rwl_write_unlock(rwl);
}

/******************************************************************************/
/******************************************************************************/
/*
 * dpdk的讀寫鎖實現, 顯然採用了讀者優先的方法, 但其加鎖的粒度已經非常的小了
 */
/******************************************************************************/
/******************************************************************************/
#ifdef __DPDK__
typedef struct
{
    volatile int32_t cnt; /**< -1 when W lock held, > 0 when R locks held. */
} rte_rwlock_t;

/******************************************************************************/
static inline void
rte_rwlock_init(rte_rwlock_t *rwl)
{
    rwl->cnt = 0;
}

/******************************************************************************/
static void inline
rte_rwlock_read_lock(rte_rwlock_t *rwl)
{
    int32_t x;
    int success = 0;

    while (success == 0)
    {
        x = rwl->cnt;
        if (x < 0)
        {
            _mm_pause;//節能減排
            continue;
        }
        success = rte_atomic32_cmpset((volatile uint32_t *)&rwl->cnt, x, x+1);
    }
}

static void inline
rte_rwlock_read_unlock(rte_rwlock_t *rwl)
{
    rte_atomic32_dec((rte_atomic32_t *)&rwl->cnt);
}

/******************************************************************************/
static void inline
rte_rwlock_write_lock(rte_rwlock_t *rwl)
{
    int32_t x;
    int success = 0;

    while (success == 0)
    {
        x = rwl->cnt;
        if (x != 0)
        {
            _mm_pause;
            continue;
        }
        success = rte_atomic32_cmpset((volatile uint32_t *)&rwl->cnt, 0, -1);
    }
}
static void inline
rte_rwlock_write_unlock(rte_rwlock_t *rwl)
{
    rte_atomic32_inc((rte_atomic32_t *)&rwl->cnt);
}
#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __READ_WRITE_LOCK_H__ */
</span>


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章