线程安全问题+读写者问题

小白苦学IT的博客主页

初学者必看:Linux操作系统入门

代码仓库:Linux代码仓库

❤关注我一起讨论和学习Linux系统

1.什么是线程安全问题?

线程安全问题是指在多线程环境中,当多个线程同时访问共享数据时,由于操作顺序的不确定性,可能导致数据的不一致性或错误。简单来说,就是当一个线程访问的共享数据被其他线程修改时,就可能发生线程安全问题。

线程安全问题的原因主要有以下几点:

  1. 操作系统的线程调度方式:操作系统的线程是“抢占式执行,随机调度”,这意味着程序在多线程环境下的执行顺序存在很多变数,可能导致线程之间的操作冲突。
  2. 多个线程同时修改同一个变量:如果多个线程同时修改同一个变量,如执行count++操作,就有可能出现两个线程同时读取count的值,然后同时修改,再同时存入,导致count只自增了一次,而不是预期的自增两次。
  3. 内存可见性:一个线程读,一个线程写时,编译器可能优化成读寄存器或缓存,导致写线程做出的修改,读线程感知不到。
  4. 指令重排序:计算机编译器和处理器在执行程序时可能会对指令顺序进行重新排序,这也可能导致线程安全问题。

2.STL,智能指针和线程安全

STL中的容器是否是线程安全的?

C++标准模板库(STL)中的容器本身不是线程安全的。这意味着,在没有适当的外部同步机制的情况下,从多个线程同时访问同一个STL容器可能会导致数据竞争和不可预测的行为。

具体来说,当至少有一个线程在修改容器(如添加、删除元素),而其他线程正在读取或写入同一个容器时,必须使用适当的同步机制(如互斥锁)来保护对容器的访问。此外,即使STL容器本身是线程安全的,但在多线程环境下使用时,仍需要注意对迭代器的操作可能会引起容器的线程安全问题。

智能指针是否是线程安全的?

对于 unique_ptr, 由于只是在当前代码块范围内生效, 因此不涉及线程安全问题.
对于 shared_ptr, 多个对象需要共用一个引用计数变量, 所以会存在线程安全问题. 但是标准库实现的时候考虑到了这个问题, 基于原子操作(CAS)的方式保证 shared_ptr 能够高效, 原子的操作引用计数.

3.其他常见的各种锁

  • 悲观锁:在每次取数据时,总是担心数据会被其他线程修改,所以会在取数据前先加锁(读锁,写锁,行锁等),当其他线程想要访问数据时,被阻塞挂起。
  • 乐观锁:每次取数据时候,总是乐观的认为数据不会被其他线程修改,因此不上锁。但是在更新数据前,会判断其他数据在更新前有没有对数据进行修改。主要采用两种方式:版本号机制和CAS操作。
  • CAS操作:当需要更新数据时,判断当前内存值和之前取得的值是否相等。如果相等则用新值更新。若不等则失败,失败则重试,一般是一个自旋的过程,即不断重试。
  • 自旋锁,公平锁,非公平锁? 

自旋锁详解

自旋锁概念

自旋锁(spinlock)是一种轻量级的锁机制,用于实现保护共享资源的目的。在多线程环境中,当多个线程尝试访问同一共享资源时,自旋锁能够确保同一时刻只有一个线程能够访问该资源,从而避免数据竞争和不一致性的问题。

自旋锁工作原理

自旋锁的工作原理基于“自旋”的概念。当一个线程尝试获取已经被另一个线程占有的锁时,该线程不会立即进入睡眠状态,而是会进入一个忙等待的循环,不断检查锁的状态,直到锁被释放。这种持续检查锁状态的行为被称为“自旋”。一旦锁被释放,等待的线程会立即获取锁并继续执行。

自旋锁运用场景

  • 自旋锁适用于那些需要短暂等待的情况,因为它避免了线程的上下文切换和睡眠开销。然而,如果等待时间较长,自旋锁可能会导致CPU资源的浪费,因为等待的线程会持续占用CPU进行循环检查。
  • 自旋锁在多处理器环境中特别有用,特别是在某些资源有限的情况下。由于多线程的核心是CPU的时分片,因此通过自旋锁可以实现线程之间的同步,确保对共享资源的互斥访问。
  • 需要注意的是,自旋锁并不适用于所有场景。在长时间等待或高并发场景下,使用其他类型的锁(如互斥锁)可能更为合适。此外,自旋锁的使用也需要谨慎处理,以避免死锁和活锁等问题。

说白了就是

总之,自旋锁是一种有效的线程同步机制,能够在多线程环境中保护共享资源的安全访问。它通过忙等待的方式实现线程之间的互斥访问,适用于短暂等待的场景。

4.读者写者问题

其实我们生活学习过程中也存在很多的读者写者的问题,像我们写博客,写文章,出黑板报,做视频等这些都是典型的读者写者问题案例。

什么是读写者问题?

读者写者问题(Reader-Writer Problem)是计算机科学中的一个经典并发控制问题。该问题关注的是在多个读者(只读取数据,不修改数据)和多个写者(修改数据)之间共享数据资源时,如何保证数据的一致性和正确性,同时最大化并发性能。

具体来说,读者写者问题要解决以下几个方面的挑战:

  1. 互斥性(Mutual Exclusion):当一个写者在写入数据时,必须保证其他写者和读者都不能访问数据,以防止数据冲突和不一致。

  2. 读者优先或写者优先:这是两种常见的策略,用于决定当有读者和写者同时请求访问数据时,哪一方应该被优先处理。

    • 读者优先:当至少有一个读者正在访问数据时,新到达的读者可以立即访问,而写者需要等待直到所有读者都完成访问。这可能导致写者长时间等待,特别是在高读取频率的场景下。

    • 写者优先:当有写者请求访问数据时,系统会优先处理写者的请求,阻止新的读者访问,并等待现有的读者完成访问。这可以确保写者不会长时间等待,但可能牺牲一些读者的并发性。

  3. 读者之间的并发性:多个读者可以同时访问数据,而不会造成数据冲突,因此应该允许这种并发访问以提高效率。

  4. 饥饿问题(Starvation):必须确保系统不会陷入一种状态,使得某个或某些读者或写者永远无法访问数据资源(即避免饥饿)。

  5. 公平性(Fairness):在长时间运行的系统中,应保证读者和写者都有机会公平地访问数据资源。

为什么要有读写锁?

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

初识读写锁

读写锁(Read-Write Lock)是一种用于多线程编程的同步机制,它允许多个线程同时读取共享资源,但在有线程要对共享资源进行写操作时,要求其它线程不能执行读或写操作。这种锁机制有助于平衡读操作和写操作之间的线程同步需求,提高并发性能。

读写锁接口认识

1.初始化读写锁

int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,  
                         const pthread_rwlockattr_t *restrict attr);
  • rwlock 是一个指向读写锁对象的指针。
  • attr 是一个指向读写锁属性的指针,通常可以设置为NULL以使用默认属性。

2.销毁读写锁

int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

3.加读锁

int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);

  当多个线程持有读锁时,其他线程仍然可以获取读锁,但不能获取写锁。

4.加写锁

int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);

当写锁被持有时,其他线程(无论是读线程还是写线程)都不能获取锁。 

5.解锁

int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

6.尝试加锁

尝试加读锁:pthread_rwlock_tryrdlock
尝试加写锁:pthread_rwlock_trywrlock

这些函数尝试获取锁,如果锁已经被其他线程持有,则立即返回错误(通常是EBUSY),而不是阻塞等待。

注意:在使用读写锁时,需要确保在适当的时候释放锁,以避免死锁和资源争用问题。通常,最好在进入临界区之前获取锁,在离开临界区之后释放锁。此外,读写锁并不适用于所有场景,有时其他同步机制(如互斥锁或条件变量)可能更为合适。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/509268.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【RISC-V】如何使用release的risc-v gnu toolchain

riscv64-elf-ubuntu-22.04-gcc-nightly-2024.03.01-nightly.tar.gz 首先去release页面中获取相应的压缩包 将压缩包解压到想解压的位置,这里我选择了 mv Downloads/riscv64-elf-ubuntu-22.04-gcc-nightly-2024.03.01-nightly.tar.gz riscv64-tool-chain/然后解压…

Mac - Keychron K3 Pro 功能键改键 -via 改键配置 For Mac

前言 Keychron K3 Pro键盘连接Mac使用,顶部一排功能键,默认是Mac的多媒体功能键。F1~F12功能键,需要按:Fn F1~F12。 而在我的日常工作中,常用的是F1~F12,期望F1~F12功…

开源推荐榜【Pear Admin Flask 用python来创建后台管理系统】

最新技术高效快速开发,前后端分离模式,开箱即用。 核心模块包括:用户、角色、职位、组织机构、菜单、字典、日志、多应用管理、文件管理、定时任务等功能。 代码量少、学习简单、功能强大、轻量级、易扩展,轻松开发从现在开始&…

Web日志/招聘网站/电商大数据项目样例【实时/离线】

Web服务器日志分析项目 业务分析 业务背景 ​ 某大型电商公司,产生原始数据日志某小时达4千五万条,一天日志量月4亿两千万条。 主机规划 (可略)日志格式: 2017-06-1900:26:36101.200.190.54 GET /sys/ashx/ConfigH…

jdk1.8下载与安装

jdk1.8下载与安装 jdk1.8下载jdk1.8安装jdk环境配置环境测试 jdk1.8下载 可以通过官网来下载,但是需要Oracl账号注册,所以这里我提供了百度网盘下载链接: 链接:https://pan.baidu.com/s/1NBapId_3UbWrz_qqf95Wgg?pwddlk7 提取码…

Python100个库分享第6个—esmre

目录 专栏导读安装安装失败解决方案常见用法1:匹配邮箱常见用法2:查找HTML标签:常见用法3:替换URL链接:总结 专栏导读 🌸 欢迎来到Python办公自动化专栏—Python处理办公问题,解放您的双手 &a…

螺钉拧紧扭矩曲线的表现——SunTorque智能扭矩系统

智能扭矩系统-智能拧紧系统-扭矩自动控制系统-SunTorque 螺钉拧紧扭矩曲线是描述螺钉在拧紧过程中扭矩与转角关系的曲线。在螺钉拧紧过程中,扭矩与转角之间存在一定的关系,这种关系可以通过扭矩曲线来反映。螺钉拧紧扭矩曲线常见的不同表现主要包括以下…

nginx | nginx反向代理/负载均衡/缓存

文章目录 一、Nginx 反向代理1.1 nginx 文件结构1.2 默认的nginx配置文件1.3 实践中的 nginx.conf 二、Nginx 负载均衡2.1 热备负载均衡2.2 轮询负责均衡2.3 加权轮询负载规则2.4 ip_hash 负载均衡2.5 对特定资源实现负载均衡2.6 对不同域名实现负载均衡2.7 实现带有URL重写的负…

vue3源码解析——ref和reactive定义响应式的区别

ref 和 reactive 是 Vue 3.0 中用于定义响应式数据的两个新 API。它们有以下区别: ref 定义单个响应式数据 数据类型可以是任意类型。它通常用于定义原始数据类型为响应式数据。返回一个响应式对象,该对象包含一个 .value 属性,可用于获取和设…

在ScadaFramework里配置采集Modbus设备

ScadaFramework是一个实现SCADA功能的软件工具,经过简单配置之后,即可采集设备数据,并进行存储、监控、组态可视化,并可将数据上传至平台。 本文将介绍如何在ScadaFramework中配置,以采集Modbus协议的设备。 一、添加链…

win10配置CLion2022+ubuntu20.04远程部署

背景 在博文ubunut搭建aarch64 cuda交叉编译环境记录中,使用的ubuntu20.04虚拟机安装eclipse来交叉编译aarch64的程序,然后发送到jetson板子上执行。开发一段时间后发现eclipse IDE使用起来不太便捷,因此,考虑使用CLion IDE&…

分库分表 ——12 种分片算法

目录 前言 分片策略 标准分片策略 行表达式分片策略 复合分片策略 Hint分片策略 不分片策略 分片算法 准备工作 自动分片算法 1、MOD 2、HASH_MOD 3、VOLUME_RANGE 4、BOUNDARY_RANGE 5、AUTO_INTERVAL 标准分片算法 6、INLINE 7、INTERVAL COSID 类型算法 …

鸿蒙(HarmonyOS)ArkTs语言基础教程开发准备

本文档适用于HarmonyOS应用开发的初学者。通过构建一个简单的具有页面跳转/返回功能的应用(如下图所示),快速了解工程目录的主要文件,熟悉HarmonyOS应用开发流程。 在开始之前,您需要了解有关HarmonyOS应用的一些基本概…

【洛谷】P9240 [蓝桥杯 2023 省 B] 冶炼金属

题目链接 P9240 [蓝桥杯 2023 省 B] 冶炼金属 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 思路 这道题可以用数学的方法去做,但是我想不到😇有兴趣的可以去看看数学的题解 比较简单的思路就是二分查找,轻松简单不费脑,带你…

pygame的搭建

pygame的介绍与环境搭建 Pygame模块 安装 WindowsR打开命令窗口,输入: pip install pygame 或者安装指定版本 pip install pygame 2.3.0常用模块 在Pygame框架中有很多模块,官方网址pygame news 。 其中最常用模块的具体说明如下表所示…

【Java SE】深入理解static关键字

🥰🥰🥰来都来了,不妨点个关注叭! 👉博客主页:欢迎各位大佬!👈 文章目录 1.static关键字1.1 static的概念1.2 static的作用1.3 static的用法1.3.1 static修饰成员变量1.3.2 static修饰…

Ubuntu20安装python3.10

1、添加 deadsnakes PPA 到源列表 add-apt-repository ppa:deadsnakes/ppa apt update 2、安装 apt install python3.10 3设置默认版本为 Python3.10 查看所有python版本 ls -l /usr/bin/python* update-alternatives --install /usr/bin/python3 python3 /usr/bin/pytho…

居里亚斩获金定奖,第13届广州定制家居展见证品牌实力飞跃

2024年3月30日,第13届广州定制家居展圆满落幕。 作为年度首场定制家居专业大展,第13届广州定制家居展的展览规模达到了100,000平方米,吸引了超过350,000人次的关注,以及800多家参展企业的参与。 在百花齐放的定制家居品类中&#…

物联网监控可视化是什么?部署物联网监控可视化大屏有什么作用?

随着物联网技术的深入应用,物联网监控可视化成为了企业数字化转型的关键环节。物联网监控可视化大屏作为物联网监控平台的重要组成部分,能够实时展示物联网设备的运行状态和数据,为企业管理决策和运维监控提供了有力的支持。今天,…

第45期 | GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区,集成了生成预训练Transformer(GPT)、人工智能生成内容(AIGC)以及大语言模型(LLM)等安全领域应用的知识。在这里,您可以找…