悲观锁、乐观锁、自旋锁和读写锁

news/2024/10/20 5:48:51/

悲观锁和乐观锁

悲观锁:在每次取数据时,总是担心数据会被其他线程修改,所以会在取数据前先加锁(读锁,写锁,行 锁等),当其他线程想要访问数据时,被阻塞挂起。(互斥锁就是一种悲观锁)

乐观锁:每次取数据时候,总是乐观的认为数据不会被其他线程修改,因此不上锁。但是在更新数据前, 会判断其他数据在更新前有没有对数据进行修改。主要采用两种方式:版本号机制和CAS操作。(C++原子操作是基于CAS的乐观锁)

自旋锁

 

由于挂起等待也有一定的消耗,万一在挂起时直接再次申请锁就成功了,挂起锁的消耗就更高。自旋锁类似于在加锁时采用:

while(pthread_mutex_trylock(&mutex));

的方式加锁。很有可能会反复申请锁,浪费CPU资源,只有在临界区的时间特别短才能使用

比如抢票代码:

#include<iostream>
#include<pthread.h> 
#include<vector>
#include<string>
#include<unistd.h>
using namespace std;
int ticket = 1000;
class mutexGuard
{
public:mutexGuard(pthread_spinlock_t* pmutex){_pmutex = pmutex;pthread_spin_lock(_pmutex);}~mutexGuard(){pthread_spin_unlock(_pmutex);}
private:pthread_spinlock_t* _pmutex;};class threadDate
{
public:threadDate(const string& name, pthread_spinlock_t* pmutex):_name(name),_pmutex(pmutex){}string _name;pthread_spinlock_t* _pmutex;
};void* getTicket(void* args)
{threadDate* td = static_cast<threadDate*>(args);while(ticket > 0){{mutexGuard mg = mutexGuard(td->_pmutex);if(ticket > 0){usleep(1000);--ticket;cout << td->_name << " : " << ticket << endl;}}}delete td;return nullptr;
}int main()
{vector<pthread_t> tid(5);int cnt = 0;pthread_spinlock_t mutex;pthread_spin_init(&mutex, PTHREAD_PROCESS_PRIVATE);for(auto& e : tid){threadDate* td = new threadDate("thread ", &mutex);++cnt;td->_name += to_string(cnt);int n = pthread_create(&e, nullptr, getTicket, td);}//等待线程for(auto& e : tid){pthread_join(e, nullptr);}//销毁锁pthread_spin_destroy(&mutex);return 0;
}

但如果临界区中有IO,就不要使用自旋锁。

读写锁

在编写多线程的时候,有一种情况是十分常见的。那就是,有些公共数据修改的机会比较少。相比较改写,它们读的 机会反而高的多。通常而言,在读的过程中,往往伴随着查找的操作,中间耗时很长。给这种代码段加锁,会极大地 降低我们程序的效率。那么有没有一种方法,可以专门处理这种多读少写的情况呢? 有,那就是读写锁。

写者之间是互斥关系

读者之间没有关系

读者和写者之间是互斥且同步的关系

 

 

 


http://www.ppmy.cn/news/53879.html

相关文章

创新案例|探索 Snyk 的 PLG 团队1.6倍年度 ARR 增长背后的策略

组织架构不匹配、权责分配不清晰以及团队协作无机制是推进PLG业务面临的三大核心挑战&#xff0c;而安全软件公司Snyk以其指数级营收和估值增长的成功实践证明&#xff0c;构建合适且高效团队是助力PLG创新实现高速增长的关键&#xff0c;其经验值得借鉴。本文将通过分析Synk如…

Bindiff工具使用-[GDOUCTF 2023]L!s!

目录 题目&#xff1a; 学到的点&#xff1a; 题目&#xff1a; 打了GDOUCTF的比赛&#xff08;被暴打了hhh)&#xff0c;学到很多新东西,这里总结一下 Diff的文件是ida数据库文件&#xff0c;选择i64或者idb文件进行Diff 打开附件&#xff0c;有两个文件&#xff0c;一个…

Golang校验字符串是否JSON格式方法json.Valid源码解析

上篇文章《Golang中如何校验字符串是否为JSON格式&#xff1f;》主要讲解了使用json.Valid校验字符串是否JSON格式的使用方法&#xff0c;本文来剖析一下json.Valid方法的源码。 json.Valid方法源码 json.Valid方法定义&#xff1a; // Valid reports whether data is a val…

Linux拓展:链接库

一.说明 本篇博客介绍Linux操作系统下的链接库相关知识&#xff0c;由于相关概念已在Windows下链接库一文中介绍&#xff0c;本篇博客直接上操作。 二.静态链接库的创建和使用 1.提前看 这里主要介绍的是C语言的链接库技术&#xff0c;而在Linux下实现C语言程序&#xff0c…

支持中英双语和多种插件的开源对话语言模型,160亿参数

一、开源项目简介 MOSS是一个支持中英双语和多种插件的开源对话语言模型&#xff0c;moss-moon系列模型具有160亿参数&#xff0c;在FP16精度下可在单张A100/A800或两张3090显卡运行&#xff0c;在INT4/8精度下可在单张3090显卡运行。MOSS基座语言模型在约七千亿中英文以及代码…

如何使用git上传文件到Github远程仓库(完整详细流程)

文章目录 1.在电脑上下载Git2.配置Git3.上传Github仓库 1.在电脑上下载Git git官网下载&#xff1a;Git - Downloads (git-scm.com) 下载后安装即可。 2.配置Git 鼠标右键进入Git命令行 &#xff08;1&#xff09;设置用户名和设置用户账号&#xff08;需要是自己的注册Git…

基于dsp+fpga+AD+ENDAC的半导体运动台高速数据采集电路仿真设计(四)

整个调试验证与仿真分析分三个步骤&#xff1a;第一步是进行 PCB 检查及电气特性测试&#xff0c;主 要用来验证硬件设计是否正常工作&#xff1b;第二步进行各子模块功能测试&#xff0c;包括高速光纤串行 通信的稳定性与可靠性测试&#xff0c; A/D 及 D/A 转换特性测…

【软件测试】测试分类

文章目录 &#x1f337; 1. 按测试对像划分⭐️ &#xff08;1&#xff09;界面测试⭐️ &#xff08;2&#xff09;可靠性测试⭐️ &#xff08;3&#xff09;容错性测试⭐️ &#xff08;4&#xff09;文档测试⭐️ &#xff08;5&#xff09;兼容性测试⭐️ &#xff08;6&a…