Posix读写锁

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

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

读写锁与互斥量类似, 不过读写锁允许更高的并行性. 读写锁用于读称为共享锁, 读写锁用于写称为排它锁;

读写锁规则:

只要没有线程持有给定的读写锁用于写, 那么任意数目的线程可以持有读写锁用于读;

仅当没有线程持有某个给定的读写锁用于读或用于写时, 才能分配读写锁用于写;

Posix自旋锁

int pthread_spin_destroy(pthread_spinlock_t *lock);
int pthread_spin_init(pthread_spinlock_t *lock, int pshared);

int pthread_spin_lock(pthread_spinlock_t *lock);
int pthread_spin_trylock(pthread_spinlock_t *lock);

int pthread_spin_unlock(pthread_spinlock_t *lock);

自旋锁类似于互斥锁, 它的性能比互斥锁更高;

自旋锁与互斥锁很重要的一个区别在于: 线程在申请自旋锁的时候, 线程并不会挂起, 它总是处于忙等待的状态(一直在自旋, CPU处于空耗的状态);

自旋锁可用于以下情况:锁被持有的时间短, 而且线程并不希望在重新调度上花费太多的成本.

自旋锁通常作为底层原语用于实现其他类型的锁: 比如有些互斥锁的实现在试图获取互斥量的时候会自旋一小段时间, 只有在自旋计数到达某一阈值的时候才会休眠; 因此, 很多互斥量的实现非常搞笑, 以至于应用程序采用互斥锁的性能与曾经采用过自旋锁的性能基本上是相同的.

因此, 自旋锁只在某些特定的情况下有用, 比如在用户层, 自旋锁并不是非常有用, 除非运行在不允许抢占的实时调度类中.

读者写者问题

问题描述

一个数据对象可以为多个并发进程所共享。其中有的进程可能只需要读共享对象的内容,而其他进程可能要更新共享对象的内容。

读者:只对读感兴趣的进程;

写者:其他进程(只写,或既读又写);

规则

允许多个读者同时读取数据;

只有一个写者可以写数据;

写者在写时读者不能读,反之亦然。

/** 实现1: 运用读写锁解决”读者写者问题”
解题思路: 将需要读写的文件实现为一个字符串;
读者进程: 一次可以将该字符串全部读出, 然后打印读取信息
写者进程: 一次只能修改一个字符(该字符从A~Z循环写入), 修改之后打印写入信息
**/
//读写锁
pthread_rwlock_t rwlock;
const unsigned READERCOUNT = 2; //读者数
const unsigned WRITERCONUT = 5; //写者数

const int PAPERSIZE = 32;       //文件长度
char paper[PAPERSIZE+1];        //文件

unsigned short int write_index = 0; //写者需要写入的位置
char ch = 'A';  //写者需要写入的字母

pthread_t thread[READERCOUNT+WRITERCONUT];  //读者+写者线程

//读者线程
void *reader(void *args)
{
    int number = *(int *)args;
    delete (int *)args;

    while (true)
    {
        //获取共享锁
        pthread_rwlock_rdlock(&rwlock);
        //开始读
        printf("## reader %d was reading...\n", number);
        printf("text: %s\n", paper);
        printf("   reader %d end reading...\n", number);
        //解锁共享锁
        pthread_rwlock_unlock(&rwlock);

        sleep(1);
    }
    pthread_exit(NULL);
}
//写者线程
void *writer(void *args)
{
    int number = *(int *)args;
    delete (int *)args;
    while (true)
    {
        //获取写锁
        pthread_rwlock_wrlock(&rwlock);
        //开始写
        printf("++ writer %d was writing...\n", number);
        paper[write_index] = ch;
        write_index = (write_index+1)%PAPERSIZE;
        ch = ch+1;
        if (ch > 'Z')
            ch = 'A';
        printf("   writer %d end writing...\n", number);
        //释放写锁
        pthread_rwlock_unlock(&rwlock);

        sleep(1);
    }

    pthread_exit(NULL);
}

int main()
{
    memset(paper, 0, sizeof(paper));
    pthread_rwlock_init(&rwlock, NULL);

    for (unsigned int i = 0; i < READERCOUNT; ++i)
        pthread_create(&thread[i], NULL, reader, new int(i));
    for (unsigned int i = 0; i < WRITERCONUT; ++i)
        pthread_create(&thread[READERCOUNT+i], NULL, writer, new int(i));
    for (unsigned int i = 0; i < READERCOUNT+WRITERCONUT; ++i)
        pthread_join(thread[i], NULL);

    pthread_rwlock_destroy(&rwlock);
}

/** 实现2: 运用Posix信号量使用”读者优先”策略解决”读者写者问题”
解题思路:
如果新读者到:
   ①无读者、写者,新读者可以读;
   ②有写者等待,但有其它读者正在读,则新读者也可以读;
   ③有写者写,新读者等待。
如果新写者到:
   ①无读者,新写者可以写;
   ②有读者,新写者等待;
   ③有其它写者,新写者等待。
**/
// 需要用两个互斥量实现
pthread_mutex_t rmutex;
pthread_mutex_t wmutex;

const unsigned READERCOUNT = 5; //读者数
const unsigned WRITERCONUT = 5; //写者数

const int PAPERSIZE = 32;       //文件长度
char paper[PAPERSIZE+1];        //文件

unsigned short int write_index = 0; //写者需要写入的位置
char ch = 'A';  //写者需要写入的字母

pthread_t thread[READERCOUNT+WRITERCONUT];  //读者+写者线程

int nReader = 0;
//读者线程
void *reader(void *args)
{
    int number = *(int *)args;
    delete (int *)args;

    while (true)
    {
        pthread_mutex_lock(&rmutex);
        //如果是第一个读者, 则锁定wmutex
        if (nReader == 0)
            pthread_mutex_lock(&wmutex);
        ++ nReader;
        pthread_mutex_unlock(&rmutex);

        //开始读
        printf("## reader %d was reading...\n", number);
        printf("text: %s\n", paper);
        printf("   reader %d end reading...\n\n", number);

        pthread_mutex_lock(&rmutex);
        -- nReader;
        //如果是最后一个读者, 则解锁wmutex
        if (nReader == 0)
            pthread_mutex_unlock(&wmutex);
        pthread_mutex_unlock(&rmutex);

        sleep(1);
    }
    pthread_exit(NULL);
}

//写者线程
void *writer(void *args)
{
    int number = *(int *)args;
    delete (int *)args;
    while (true)
    {
        //获取写锁
        pthread_mutex_lock(&wmutex);
        //开始写
        printf("++ writer %d was writing...\n", number);
        paper[write_index] = ch;
        write_index = (write_index+1)%PAPERSIZE;
        ch = ch+1;
        if (ch > 'Z')
            ch = 'A';
        printf("   writer %d end writing...\n\n", number);
        //释放写锁
        pthread_mutex_unlock(&wmutex);

        sleep(1);
    }

    pthread_exit(NULL);
}

int main()
{
    memset(paper, 0, sizeof(paper));
    pthread_mutex_init(&rmutex, NULL);
    pthread_mutex_init(&wmutex, NULL);

    for (unsigned int i = 0; i < READERCOUNT; ++i)
        pthread_create(&thread[i], NULL, reader, new int(i));
    for (unsigned int i = 0; i < WRITERCONUT; ++i)
        pthread_create(&thread[READERCOUNT+i], NULL, writer, new int(i));
    for (unsigned int i = 0; i < READERCOUNT+WRITERCONUT; ++i)
        pthread_join(thread[i], NULL);

    pthread_mutex_destroy(&rmutex);
    pthread_mutex_destroy(&wmutex);
}

“读者优先”思想小结: 读者优先的设计思想是读进程只要看到有其它读进程正在读,就可以继续进行读;写进程必须等待所有读进程都不读时才能写,即使写进程可能比一些读进程更早提出申请。该算法只要还有一个读者在活动,就允许后续的读者进来,该策略的结果是,如果有一个稳定的读者流存在,那么这些读者将在到达后被允许进入。而写者就始终被挂起,直到没有读者为止.

Linux多线程实践(6) --Posix读写锁解决读者写者问题的更多相关文章

  1. Linux多线程实践(8) --Posix条件变量解决生产者消费者问题

    Posix条件变量 int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr); int pthread_co ...

  2. Linux多线程实践(5) --Posix信号量与互斥量解决生产者消费者问题

    Posix信号量 Posix 信号量 有名信号量 无名信号量 sem_open sem_init sem_close sem_destroy sem_unlink sem_wait sem_post ...

  3. C#使用读写锁解决多线程并发写入文件时线程同步的问题

    读写锁是以 ReaderWriterLockSlim 对象作为锁管理资源的,不同的 ReaderWriterLockSlim 对象中锁定同一个文件也会被视为不同的锁进行管理,这种差异可能会再次导致文件 ...

  4. FileShare文件读写锁解决“文件XXX正由另一进程使用,因此该进程无法访问此文件”(转)

    开发过程中,我们往往需要大量与文件交互,读文件,写文件已成家常便饭,本地运行完美,但一上到投产环境,往往会出现很多令人措手不及的意外,或开发中的烦恼,因此,我对普通的C#文件操作做了一次总结,问题大部 ...

  5. 四十、Linux 线程——互斥锁和读写锁

    40.1 互斥锁 40.1.1 介绍 互斥锁(mutex)是一种简单的加锁的方法来控制对共享资源的访问. 在同一时刻只能有一个线程掌握某个互斥锁,拥有上锁状态的线程能够对共享资源进行访问. 若其他线程 ...

  6. 22、Java并发性和多线程-Java中的读/写锁

    以下内容转自http://ifeve.com/read-write-locks/: 相比Java中的锁(Locks in Java)里Lock实现,读写锁更复杂一些.假设你的程序中涉及到对一些共享资源 ...

  7. linux线程间同步(1)读写锁

    读写锁比mutex有更高的适用性,能够多个线程同一时候占用读模式的读写锁.可是仅仅能一个线程占用写模式的读写锁. 1. 当读写锁是写加锁状态时,在这个锁被解锁之前,全部试图对这个锁加锁的线程都会被堵塞 ...

  8. Linux IPC实践(10) --Posix共享内存

    1. 创建/获取一个共享内存 #include <sys/mman.h> #include <sys/stat.h> /* For mode constants */ #inc ...

  9. Linux多线程实践(六)使用Posix条件变量解决生产者消费者问题

    前面的一片文章我们已经讲过使用信号量解决生产者消费者问题.那么什么情况下我们须要引入条件变量呢? 这里借用  http://www.cnblogs.com/ngnetboy/p/3521547.htm ...

随机推荐

  1. 吴恩达深度学习第1课第4周-任意层人工神经网络(Artificial Neural Network,即ANN)(向量化)手写推导过程(我觉得已经很详细了)

    学习了吴恩达老师深度学习工程师第一门课,受益匪浅,尤其是吴老师所用的符号系统,准确且易区分. 遵循吴老师的符号系统,我对任意层神经网络模型进行了详细的推导,形成笔记. 有人说推导任意层MLP很容易,我 ...

  2. python学习之路基础篇(三)

    博客参考:http://www.cnblogs.com/wupeiqi/articles/4943406.html http://www.cnblogs.com/luotianshuai/p/4949 ...

  3. DOS/Windows 文本格式与 Unix 文本各式转换

    命令简介: dos2unix是将Windows格式文件转换为Unix.Linux格式的实用命令.Windows格式文件的换行符为\r\n ,而Unix&Linux文件的换行符为\n. dos2 ...

  4. 衣带渐宽终不悔,为伊消得人憔悴--DbHelper增强版

    核心理念 如何使用 测试实例 数据库内详细数据信息 测试代码 数据库连接池测试 测试集 延伸 相关下载链接 前几日,写了一篇关于一个 轻量级数据持久化的框架的博客(点击浏览: http://blog. ...

  5. Android图表库MPAndroidChart(十二)——来点不一样的,正负堆叠条形图

    Android图表库MPAndroidChart(十二)--来点不一样的,正负堆叠条形图 接上篇,今天要说的,和上篇的类似,只是方向是有相反的两面,我们先看下效果 实际上这样就导致了我们的代码是比较类 ...

  6. springMVC源码分析--HandlerAdapter(一)

    HandlerAdapter的功能实际就是执行我们的具体的Controller.Servlet或者HttpRequestHandler中的方法. 类结构如下:

  7. Excel 、数据库 一言不合就转换

    Excel 与数据库 对于从事相关行业的小伙伴们而言,可谓是再熟悉不过了,但是面对这两者的转换,你是否已经手忙脚乱,乃至焦头烂额? 还好,今后你将不再受此折磨.不再有日日夜夜加班导入数据的枯燥工作,不 ...

  8. Gazebo機器人仿真學習探索筆記(七)连接ROS

    中文稍后补充,先上官方原版教程.ROS Kinetic 搭配 Gazebo 7 附件----官方教程 Tutorial: ROS integration overview As of Gazebo 1 ...

  9. 阿里云手动安装特定版本的nginx

    想添加nginx的缓存功能, 结果1.4.6还不支持. apt-get remove nginx 374 sudo apt-key add nginx_signing.key 375 deb http ...

  10. python 函数运算先于单目运算

    >>> def f(): >>> -f() - 初一看,-f()比较陌生的样子,细想,这是合理的