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);//如果是第一个读者, 则锁定wmutexif (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;//如果是最后一个读者, 则解锁wmutexif (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. 用信号量和读写锁解决读者写者问题

    用信号量和读写锁解决读者写者问题 参考文章: (1)用信号量和读写锁解决读者写者问题 (2)https://www.cnblogs.com/xybaby/p/6559212.html 备忘一下.

  2. 使用读写锁解决读者-写者问题

    读写锁 读写锁适合于对数据结构的读次数比写次数多得多的情况.因为,读模式锁定时可以共享,以写 模式锁住时意味着独占,所以读写锁又叫共享-独占锁. 初始化和销毁: #include <pthrea ...

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

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

  4. Linux多线程开发-线程同步-读写锁pthread_rwlock_t

    1.读写锁概念 对资源的访问抽象为两种类型,即独占和共享.独占资源具有排他性,例如写操作.共享资源可以同时由多个线程访问,不对该资源执行写操作.针对资源的读和写操作分别加锁,写操作加锁与互斥锁相同,但 ...

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

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

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

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

  7. Gox语言中使用读写锁解决并发冲突以及如何实现线程同步归并-GX22

    Gox语言中,除了可以直接使用Go语言中的通道对象(chan)之外,也直接引入了Go语言标准库中的sync包,因此可以直接使用共享锁Mutex对象或者读写锁RWMutex对象来处理并发操作中共享数据安 ...

  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. 用泛型方法Java从实体中提取属性值,以及在泛型方法中的使用
  2. K-means算法(理论+opencv实现)
  3. PonyAI小马智行官宣再获2.67亿美元融资,创办4年累计吸金超10亿美元
  4. DataSnap如何监控Tcp/IP客户端的连接情况
  5. IEnumerableT和IQueryableT区分
  6. Logstash 基础入门
  7. 深度置信网络 Deep belief network
  8. 狗都能看懂的Pytorch MAML代码详解
  9. Unity编辑器扩展——撤回
  10. word表格内文字行间距调整方法
  11. js设计模式--代理模式
  12. Vue中的component
  13. 字符串分割 strsep 函数
  14. 关于ROS功能包里package.xml和CMakeList.txt的源码分析
  15. 主板四大厂_(【四大品牌主板真假图片对比之技嘉】- 中关村在线)
  16. 老韩思考:为什么毕业后3年,同学之间相差如此大?
  17. 第一章 无线通信收发机结构 杨远望 和习题
  18. 如何使用 mps 开发原生小程序
  19. 再思考如何正确的致富
  20. 在JavaScript中每5秒调用一个函数

热门文章

  1. 使用unix工具监控cpu、内存等系统资源占用率
  2. Java拦截过滤器模式
  3. @HostListener 可接收的事件列表
  4. 在请求完成后回调delegate的方法。然而回调时经常遇到这种情况:delegate已经被释放...
  5. T-SQL笔记3:事务、锁定和并发
  6. JavaScript中的正则表达式解析
  7. 使用ASP.NET Atlas编写显示真实进度的ProgressBar(进度条)控件
  8. Oracle使用手册(三)---存储过程与触发器
  9. im和音视频开发哪个更好_找时间成为更好的开发人员
  10. rhel-server-7.5-x86_64-dvd.iso镜像下载及rar压缩包的解压