什么是读写锁
读写锁其实还是一种锁,是给一段临界区代码加锁,但是此加锁是在进行写操作的时候才会互斥,而在进行读的时候是可以共享的进行访问临界区的
为什么需要读写锁
有时候,在多线程中,有一些公共数据修改的机会比较少,而读的机会却是非常多的,此公共数据的操作基本都是读,如果每次操作都给此段代码加锁,太浪费时间了而且也很浪费资源,降低程序的效率,因为读操作不会修改数据,只是做一些查询,所以在读的时候不用给此段代码加锁,可以共享的访问,只有涉及到写的时候,互斥的访问就好了
读写锁的分配规则:
1 只要没有线程持有某个给定的读写锁用于写,那么任意数目的线程可以持有该读写锁用于读
2 仅当没有线程持有某个给定的读写锁用于读或用于写时候,才能分配该读写锁用于写。
归纳起来就是下面的原则:
1读写锁是"写模式加锁"时, 解锁前,所有对该锁加锁的线程都会被阻塞。
2读写锁是"读模式加锁"时, 如果线程以读模式对其加锁会成功;如果线程以写模式加锁会阻塞。
3读写锁是"读模式加锁"时, 既有试图以写模式加锁的线程,也有试图以读模式加锁的线程。那么读写锁会阻塞随后的读模式锁请求。优先满足写模式锁。读锁、写锁并行阻塞,写锁优先级高

读写锁的相关函数:
1 #include <pthread.h>
int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr);
如果attr为NULL,则使用缺省的读写锁属性,其作用与传递缺省读写锁属性对象的地址相同。初始化读写锁之后,该锁可以使用任意次数,而无需重新初始化。成功初始化之后,读写锁的状态会变为已初始化和未锁定。如果调用pthread_rwlock_init()来指定已初始化的读写锁,则结果是不确定的。如果读写锁在使用之前未初始化,则结果是不确定的。
如果成功,pthread_rwlock_init()会返回零。否则,将返回用于指明错误的错误号。如果pthread_rwlock_init()失败,将不会初始化rwlock,并且rwlock的内容是不确定
int  pthread_rwlock_rdlock(pthread_rwlock_t *rwlock );
如果写入器未持有读锁,并且没有任何写入器基于该锁阻塞,则调用线程会获取读锁。如果写入器未持有读锁,但有多个写入器正在等待该锁时,调用线程是否能获取该锁是不确定的。如果某个写入器持有读锁,则调用线程无法获取该锁。如果调用线程未获取读锁,则它将阻塞。调用线程必须获取该锁之后,才能从pthread_rwlock_rdlock()返回。如果在进行调用时,调用线程持有rwlock中的写锁,则结果是不确定的。

int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
如果获取了用于在rwlock所引用的读写锁对象中执行读取的锁,则pthread_rwlock_tryrdlock()将返回零。如果没有获取该锁,则返回用于指明错误的错误号。

int  pthread_rwlock_wrlock(pthread_rwlock_t *rwlock );
如果没有其他读取器线程或写入器线程持有读写锁rwlock,则调用线程将获取写锁。否则,调用线程将阻塞。调用线程必须获取该锁之后,才能从pthread_rwlock_wrlock()调用返回。如果在进行调用时,调用线程持有读写锁(读锁或写锁),则结果是不确定的

int pthread_rwlock_trywrlock(pthread_rwlock_t  *rwlock);
如果针对未初始化的读写锁调用pthread_rwlock_trywrlock(),则结果是不确定的。
线程信号处理程序可以处理传送给等待读写锁以执行写入的线程的信号。从信号处理程序返回后,线程将继续等待读写锁以执行写入,就好像线程未中断一样

int pthread_rwlock_unlock (pthread_rwlock_t  *rwlock);
如果通过调用pthread_rwlock_unlock()来释放读写锁对象中的读锁,并且其他读锁当前由该锁对象持有,则该对象会保持读取锁定状态。如果pthread_rwlock_unlock()释放了调用线程在该读写锁对象中的最后一个读锁,则调用线程不再是该对象的属主。如果pthread_rwlock_unlock()释放了该读写锁对象的最后一个读锁,则该读写锁对象将处于无属主、解除锁定状态。
如果通过调用pthread_rwlock_unlock()释放了该读写锁对象的最后一个写锁,则该读写锁对象将处于无属主、解除锁定状态。
如果pthread_rwlock_unlock()解除锁定该读写锁对象,并且多个线程正在等待获取该对象以执行写入,则通过调度策略可确定获取该对象以执行写入的线程。如果多个线程正在等待获取读写锁对象以执行读取,则通过调度策略可确定等待线程获取该对象以执行写入的顺序。如果多个线程基于rwlock中的读锁和写锁阻塞,则无法确定读取器和写入器谁先获得该锁

int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
在再次调用pthread_rwlock_init()重新初始化该锁之前,使用该锁所产生的影响是不确定的。实现可能会导致pthread_rwlock_destroy()将rwlock所引用的对象设置为无效值。如果在任意线程持有rwlock时调用pthread_rwlock_destroy(),则结果是不确定的。尝试销毁未初始化的读写锁会产生不确定的行为。已销毁的读写锁对象可以使用pthread_rwlock_init()来重新初始化。销毁读写锁对象之后,如果以其他方式引用该对象,则结果是不确定的

来个看具体的例子:
pthread_write中获取写锁,每次都对value值增加50,当超过500的时候就不再增加
pthread_rwlock_t rwlock;
int value;
void *pthread_write(void *arg)
{
    int i=(int)arg;
    while(value <= 500)
    {
        pthread_rwlock_wrlock(&rwlock);
        printf("value=%d,thread_id=%d -------write\n",value+=50,i);
        pthread_rwlock_unlock(&rwlock);
        sleep(1);
    }
    return NULL;
}
pthread_read中获取读锁,并读取value的值
void *pthread_read(void *arg)
{
    int i=(int)arg;
    while(value <= 500)
    {
        pthread_rwlock_rdlock(&rwlock);
        printf("value=%d,thread_id=%d -------read\n",value,i);
        pthread_rwlock_unlock(&rwlock);
        sleep(1);
    }
    return NULL;
}
在read_write_test中创建10个流程,其中5个用于写,5个用于读。当value值大于500的时候,取消掉线程。
void read_write_test()
{
    int i;
    pthread_t pt[10];
    pthread_rwlock_init(&rwlock,NULL);
    value=0;
    for(i=0;i<5;i++)
    {
        pthread_create(&pt[i],NULL,pthread_write,(void *)i);
    }

for(i=5;i<10;i++)
    {
        pthread_create(&pt[i],NULL,pthread_read,(void *)i);
    }
    for(i=0;i<10;i++)
    {
        pthread_join(pt[i],NULL);
    }
    while(1)
    {
        printf("value=%d\n",value);
        if(value >=500)
        {
            for(int j=0;j<10;j++)
            {
                pthread_cancel(pt[j]);
                pthread_join(pt[j],NULL);
            }
        }
        break;
    }
    pthread_rwlock_destroy(&rwlock);
}
运行结果如下:当超过500的时候,线程被取消

linux c编程:读写锁的更多相关文章

  1. Linux系统编程 —读写锁rwlock

    读写锁是另一种实现线程间同步的方式.与互斥量类似,但读写锁将操作分为读.写两种方式,可以多个线程同时占用读模式的读写锁,这样使得读写锁具有更高的并行性. 读写锁的特性为:写独占,读共享:写锁优先级高. ...

  2. java并发编程-读写锁

    最近项目中需要用到读写锁 读写锁适用于读操作多,写操作少的场景,假设你的程序中涉及到对一些共享资源的读和写操作,且写操作没有读操作那么频繁.在没有写操作的时候,两个线程同时读一个资源没有任何问题,所以 ...

  3. 嵌入式 Linux线程同步读写锁rwlock示例

    读写锁比mutex有更高的适用性,可以多个线程同时占用读模式的读写锁,但是只能一个线程占用写模式的读写锁.1. 当读写锁是写加锁状态时,在这个锁被解锁之前,所有试图对这个锁加锁的线程都会被阻塞:2. ...

  4. Linux:使用读写锁使线程同步

    基础与控制原语 读写锁 与互斥量类似,但读写锁允许更高的并行性.其特性为:写独占,读共享. 读写锁状态: 一把读写锁具备三种状态:     1. 读模式下加锁状态 (读锁)     2. 写模式下加锁 ...

  5. JAVA 并发编程-读写锁之模拟缓存系统(十一)

    在多线程中,为了提高效率有些共享资源同意同一时候进行多个读的操作,但仅仅同意一个写的操作,比方一个文件,仅仅要其内容不变能够让多个线程同一时候读,不必做排他的锁定,排他的锁定仅仅有在写的时候须要,以保 ...

  6. Linux的线程同步对象:互斥量Mutex,读写锁,条件变量

        进程是Linux资源分配的对象,Linux会为进程分配虚拟内存(4G)和文件句柄等 资源,是一个静态的概念.线程是CPU调度的对象,是一个动态的概念.一个进程之中至少包含有一个或者多个线程.这 ...

  7. Linux程序设计学习笔记----多线程编程线程同步机制之相互排斥量(锁)与读写锁

    相互排斥锁通信机制 基本原理 相互排斥锁以排他方式防止共享数据被并发訪问,相互排斥锁是一个二元变量,状态为开(0)和关(1),将某个共享资源与某个相互排斥锁逻辑上绑定之后,对该资源的訪问操作例如以下: ...

  8. Linux环境编程之同步(三):读写锁

    概述 相互排斥锁把试图进入我们称之为临界区的全部其它线程都堵塞住.该临界区通常涉及对由这些线程共享一个或多个数据的訪问或更新.读写锁在获取读写锁用于读某个数据和获取读写锁用于写直接作差别. 读写锁的分 ...

  9. linux c 线程间同步(通信)的几种方法--互斥锁,条件变量,信号量,读写锁

    Linux下提供了多种方式来处理线程同步,最常用的是互斥锁.条件变量.信号量和读写锁. 下面是思维导图:  一.互斥锁(mutex)  锁机制是同一时刻只允许一个线程执行一个关键部分的代码. 1 . ...

随机推荐

  1. 李洪强和你一起学习前端之(3)Css基础和选择器

    大家好! 经过了前面的学习,是不是对前端的学习有了初步的了解.虽然我之前有iOS开发的经验,现在接触一门新的语言,对我来说 有一定的优势,但是一门技术对于谁来说都是公平的,我承认,我在接触新知识的时候 ...

  2. BootCamp支持软件6

    最新版本的 Boot Camp 6 苹果驱动支持的机型列表 苹果官方已经公布了 BootCamp 6 驱动支持的机型列表了,基本上 2012 年后的 Macbook / Pro / Air / iMa ...

  3. 由Python的一个小例子想到的

    习题: L = [1,2] L.append(L) Print L 问,结果是什么. 结果是,[1,2,[...]] 这是什么意思呢?就是说[...]表示的对[1,2]的无限循环.这一点是在C#等静态 ...

  4. gm: error while loading shared libraries: libpng15.so.15: cannot open shared object file: No such file or directory

    安装gm库产生问题 解决方案: # cat /etc/ld.so.confinclude ld.so.conf.d/*.conf# echo "/usr/local/lib" &g ...

  5. windows下SVN服务的安装与配置

    第一步 下载 去svn官网下载一个最新版的svn svn官网下载地址 该链接会跳转到 https://sourceforge.net/projects/win32svn/ 进行下载 第二步 安装 双击 ...

  6. MonoTouch

    本文为2012年4月19日Xamarin研讨会OLO在线咨询高级软件工程师Greg Shackles的一份的演讲资料. 本文为2012年4月19日Xamarin研讨会OLO在线咨询高级软件工程师Gre ...

  7. Matlab之合并音频

    程序功能: 1.读入wav下的所有音频 2.每个音频截取前0.6秒 3.合并每个音频 clear all; cd = 'wav'; waveFiles = dir(fullfile(cd,'*.wav ...

  8. 第二百零六节,jQuery EasyUI,Menu(菜单)组件

    jQuery EasyUI,Menu(菜单)组件 学习要点: 1.加载方式 2.菜单项属性 3.菜单属性 4.菜单事件 5.菜单方法 本节课重点了解 EasyUI 中 Menu(菜单)组件的使用方法, ...

  9. mui 单页面下拉刷新

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  10. 五月的仓颉大神写的 三年java程序员面试感悟 值得分享给大家

    感谢 五月的仓颉  的这篇文章 , 让我重新认识到自己身上的不足之处 .  原文地址http://www.cnblogs.com/xrq730/p/5260294.html,转载请注明出处,谢谢! 前 ...