当前位置: 首页 > news >正文

Linux 线程安全 (2)

文章目录

  • 线程同步概念
  • 条件变量使用
  • 生产消费模型
  • 信号量的使用
  • 读写锁的使用

Linux 线程安全 (1)

线程同步概念

竞态条件:因为时序问题,而导致程序异常.

饥饿问题:只使用互相锁保证线程安全时,锁资源总被某一个线程占用的情况。

线程同步:线程同步是指在多线程编程中,为了保证临界资源的正确访问和避免竞态条件,需要协调和控制线程之间的执行顺序和互斥访问。让线程能够按照某种特定的顺序访问临界资源,从而有效避免饥饿问题。常见的线程同步机制包括互斥锁(Mutex)、信号量(Semaphore)、条件变量(Condition Variable)等。

条件变量使用

在多线程编程中,有需要等待某个资源就绪,线程才能开始正常运行的需求。
例如一个线程访问队列时,发现队列为空,它只能等待,只到其它线程将一个节点添加到队列中。这种情况就需要用到条件变量。

条件变量是一种线程同步的高级机制,它可以实现线程的等待和唤醒操作。条件变量通常与互斥锁一起使用,当某个条件不满足时,线程可以调用条件变量的等待操作进入等待状态,当条件满足时,其他线程可以调用条件变量的唤醒操作来唤醒等待的线程。

// 1.初始化条件变量 
//cond为要初始化的条件变量
int pthread_cond_init(pthread_cond_t *restrict cond,
const pthread_condattr_t *restrict attr);
//2.等待条件满足 
int pthread_cond_wait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex);
//3.唤醒等待
//唤醒所有在等待的线程
int pthread_cond_broadcast(pthread_cond_t *cond);
//随机唤醒一个真在等待的线程
int pthread_cond_signal(pthread_cond_t *cond);

例子

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>pthread_cond_t cond;
pthread_mutex_t mutex;void *r1( void *arg )
{while ( 1 ){pthread_cond_wait(&cond, &mutex);printf("活动\n");}
}void *r2(void *arg )
{while ( 1 ) {pthread_cond_signal(&cond);sleep(1);}
}int main( void )
{pthread_t t1, t2;pthread_cond_init(&cond, NULL);pthread_mutex_init(&mutex, NULL);pthread_create(&t1, NULL, r1, NULL);pthread_create(&t2, NULL, r2, NULL);pthread_join(t1, NULL);pthread_join(t2, NULL);pthread_mutex_destroy(&mutex);pthread_cond_destroy(&cond);
}

条件变量实际使用规范
①等待条件代码

pthread_mutex_lock(&mutex);
while (条件为假)
pthread_cond_wait(cond, mutex);
修改条件
pthread_mutex_unlock(&mutex);

②给条件发送信号代码

pthread_mutex_lock(&mutex);
设置条件为真
pthread_cond_signal(cond);
pthread_mutex_unlock(&mutex);

"条件” 可以理解为需要等待就绪的资源。
条件为假:线程代码运行需要的资源未就绪。
条件为真:线程代码运行需要的资源就绪。
修改条件:使用资源。

生产消费模型

产者消费者模型是一种常见的并发编程模型,用于解决多线程环境下的生产者和消费者之间的协作问题。在这个模型中,生产者负责生产数据,并将数据放入共享的缓冲区中,而消费者则负责从缓冲区中取出数据并进行消费。

该模型的基本思想是通过一个共享的缓冲区来实现生产者和消费者之间的同步与通信。生产者在生产数据之前会检查缓冲区是否已满,如果已满则等待,直到有空闲位置。而消费者在消费数据之前会检查缓冲区是否为空,如果为空则等待,直到有数据可供消费。

为了实现这种同步与通信,可以使用互斥锁(mutex)来保护缓冲区的访问,以及条件变量(condition variable)来实现生产者和消费者之间的等待和通知机制。

在这里插入图片描述

信号量的使用

此处的信号量使用指的是对POSIX信号量的使用,POSIX信号量可以用于线程间同步。

//1.初始化信号量
//pshared=0表示线程间共享信号量
//value 表示信号量的初始值
int sem_init(sem_t *sem, int pshared, unsigned int value);
//2.等待信号量,会将信号量的值减
int sem_wait(sem_t *sem);
//3.发布信号量,表示资源使用完毕,可以归还资源了。将信号量值加1
int sem_post(sem_t *sem);
//4.销毁信号量
int sem_destroy(sem_t *sem);
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>#define NUM_THREADS 5sem_t semaphore;void* thread_function(void* arg) 
{int thread_id = *(int*)arg;printf("Thread %d is waiting...\n", thread_id);sem_wait(&semaphore);printf("Thread %d has acquired the semaphore.\n", thread_id);// 模拟线程执行一些任务sleep(2);printf("Thread %d is releasing the semaphore.\n", thread_id);sem_post(&semaphore);pthread_exit(NULL);
}int main() 
{pthread_t threads[NUM_THREADS];int thread_ids[NUM_THREADS];// 初始化信号量,初始值为1sem_init(&semaphore, 0, 1);// 创建多个线程for (int i = 0; i < NUM_THREADS; i++) {thread_ids[i] = i;pthread_create(&threads[i], NULL, thread_function, &thread_ids[i]);}// 等待所有线程结束for (int i = 0; i < NUM_THREADS; i++) {pthread_join(threads[i], NULL);}// 销毁信号量sem_destroy(&semaphore);return 0;
}

读写锁的使用

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

使用

// 1. 设置读写优先级
// attr指向要设置属性的读写锁的指针
// pref 共有3种选择
//PTHREAD_RWLOCK_PREFER_READER_NP:优先选择读者。
//PTHREAD_RWLOCK_PREFER_WRITER_NP:优先选择写者。
//PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP:优先选择非递归写者。
int pthread_rwlockattr_setkind_np(pthread_rwlockattr_t *attr, 
int pref);//2. 初始化
//rwlock用于指定要初始化的读写锁对象。
//attr设置为nullptr
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,
const pthread_rwlockattr_t *restrict attr);//3. 加锁和解锁/*pthread_rwlock_rdlock函数用于获取读写锁的读取锁定。
读取锁定允许多个线程同时持有锁,只要没有线程持有写入锁。
如果有线程持有写入锁,则其他线程尝试获取读取锁会被阻塞,直到写入锁被释放。*/
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);/*
pthread_rwlock_wrlock函数用于获取读写锁的写入锁定。
写入锁定是独占的,只能由一个线程持有。如果有线程持有读取锁或写入锁,
则其他线程尝试获取写入锁会被阻塞,直到所有读取锁和写入锁都被释放
*/
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);//用于释放读写锁
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

实际使用:

#include <stdio.h>
#include <pthread.h>// 共享资源
int shared_data = 0;// 读写锁
pthread_rwlock_t rwlock;// 读线程函数
void* reader_function(void* arg) 
{int thread_id = *(int*)arg;while (1) {// 获取读锁pthread_rwlock_rdlock(&rwlock);// 读取共享资源printf("Reader %d reads shared data: %d\n", thread_id, shared_data);// 释放读锁pthread_rwlock_unlock(&rwlock);// 等待一段时间sleep(1);}pthread_exit(NULL);
}// 写线程函数
void* writer_function(void* arg) 
{int thread_id = *(int*)arg;while (1) {// 获取写锁pthread_rwlock_wrlock(&rwlock);// 修改共享资源shared_data++;printf("Writer %d updates shared data: %d\n", thread_id, shared_data);// 释放写锁pthread_rwlock_unlock(&rwlock);// 等待一段时间sleep(2);}pthread_exit(NULL);
}int main() 
{pthread_t readers[3];pthread_t writers[2];int reader_ids[3] = {1, 2, 3};int writer_ids[2] = {1, 2};// 初始化读写锁pthread_rwlock_init(&rwlock, NULL);// 创建读线程for (int i = 0; i < 3; i++) {pthread_create(&readers[i], NULL, reader_function, &reader_ids[i]);}// 创建写线程for (int i = 0; i < 2; i++) {pthread_create(&writers[i], NULL, writer_function, &writer_ids[i]);}// 等待读线程结束for (int i = 0; i < 3; i++) {pthread_join(readers[i], NULL);}// 等待写线程结束for (int i = 0; i < 2; i++) {pthread_join(writers[i], NULL);}// 销毁读写锁pthread_rwlock_destroy(&rwlock);return 0;
}

在这里插入图片描述

相关文章:

Linux 线程安全 (2)

文章目录 线程同步概念条件变量使用生产消费模型信号量的使用读写锁的使用 Linux 线程安全 &#xff08;1&#xff09; 线程同步概念 竞态条件&#xff1a;因为时序问题&#xff0c;而导致程序异常. 饥饿问题&#xff1a;只使用互相锁保证线程安全时&#xff0c;锁资源总被某…...

异或运算^简述

异或运算&#xff1a;^ 两个变量之间异或运算时&#xff0c;其二进制位相同取0&#xff0c;不同取1. 示例&#xff1a;a10 (0b 0000 1010) b3 (0b 0000 0011) a^b9(0b 0000 1001) 据此可以推算异或运算"^"有以下特性&#xff1a; a^a0 (0b 0000 0000)…...

Google Play上架:2023年度总结报告

今天是2023年的最后一个工作日&#xff0c;今天用来总结一下2023年关于谷歌商店上架的相关政策改动和对应的拒审解决方法。 目录 政策更新与改动2023 年 2 月 22 日2023 年 4 月5 日2023 年 7 月 12 日2023 年 10 月 25 日 开发者计划政策拒审邮件内容和解决办法 政策更新与改…...

JAVA进化史: JDK10特性及说明

DK 10&#xff08;Java Development Kit 10&#xff09;是Java平台的一个版本&#xff0c;于2018年3月发布。尽管相对于之前的版本&#xff0c;JDK 10的变化较为温和&#xff0c;但仍然引入了一些新特性和改进&#xff0c;以下是其中一些主要特性&#xff0c;并带有相应的示例说…...

第二百三十四回

文章目录 1.概念介绍2.使用方法2.1 NumberPicker2.2 CupertinoPicker 3.示例代码4.内容总结 我们在上一章回中介绍了"如何在任意位置显示PopupMenu"相关的内容&#xff0c;本章回中将介绍如何实现NumberPicker.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1.概念…...

{MySQL} 数据库约束 表的关系 新增删除 修改 查询

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、数据库约束1.1约束类型&#xff1a;1.2 NULL约束1.3unique 唯一约束1.4 DEFAULT&#xff1a;默认值约束1.5 PRIMARY KEY&#xff1a;主键约束1.6 FOREIGN K…...

【JVM】虚拟机的组成+字节码文件组成+类的生命周期

什么是JVM&#xff1f; JVM 本质上是一个运行在计算机上的程序&#xff0c;他的职责是运行Java字节码文件。 JVM的功能 1.解释和运行&#xff1a;对字节码文件中的指令实时的解释成机器码让计算机执行。 2.内存管理&#xff1a;自动为对象、方法等分配内存&#xff0c;自动…...

pip 下载太慢的解决办法,pip换国内源,pip换源

用pip安装python包的时候&#xff0c;如果系统没有进行相关设置&#xff0c;则用的源服务器是国外的&#xff0c;在国内访问非常慢&#xff0c;我们需要换成国内的源服务器&#xff0c;pip换源通过如下命令&#xff1a; pip config set global.index-url <源地址> 一、…...

OKCC语音机器人的人机耦合来啦

目前市场上语音机器人的外呼形式基本就分为三种&#xff0c;一种纯AI外呼&#xff0c;第二种也是目前主流的AI外呼转人工。那么第三种也可能是未来的一种趋势&#xff0c;人机耦合&#xff0c;或者也叫人机协同。 那么什么是人机耦合呢&#xff1f; 人机耦合是为真人坐席创造相…...

有序数组的平方

给你一个按 非递减顺序 排序的整数数组 nums&#xff0c;返回 每个数字的平方 组成的新数组&#xff0c;要求也按 非递减顺序 排序。 示例 1&#xff1a; 输入&#xff1a;nums [-4,-1,0,3,10] 输出&#xff1a;[0,1,9,16,100] 解释&#xff1a;平方后&#xff0c;数组变为 …...

Java虚拟机中的垃圾回收

2 垃圾回收 2.1 判断一个对象是否可回收 2.1.1 引用计数法 如果一个对象被另一个对象引用&#xff0c;那么它的引用计数加一&#xff0c;如果那个对象不再引用它了&#xff0c;那么引用计数减一。当引用计数为 0 时&#xff0c;该对象就应该被垃圾回收了。 但是下面这种互相…...

Vscode新手安装与使用

安装与版本选择 VS Code 有两个不同的发布渠道&#xff1a;一个是我们经常使用的稳定版&#xff08;Stable&#xff09;&#xff0c;每个月发布一个主版本&#xff1b;另外一个发布渠道叫做 Insiders&#xff0c;每周一到周五 UTC 时间早上6点从最新的代码发布一个版本&#x…...

以元旦为题的诗词(二)

都放假了吧&#xff0c;都有空了吧&#xff0c;可坐下来好好学学诗词&#xff0c;好好写些诗词了吧&#xff0c;我先来几首&#xff0c;你实在不行&#xff0c;去百度或者小程序搜索《美诗计》写一写 元旦 去年元日落寒灰&#xff0c;今岁清明在此杯 老眼看书如梦寐&#xff…...

饥荒Mod 开发(二一):超大便携背包,超大物品栏,永久保鲜

饥荒Mod 开发(二十):显示打怪伤害值 饥荒Mod 开发(二二):显示物品信息 源码 游戏中的物品栏容量实在太小了,虽然可以放在箱子里面但是真的很不方便,外出一趟不容易看到东西都不能捡。实在是虐心。 游戏中的食物还有变质机制,时间长了就不能吃了,玩这个游戏心里压力真是太…...

js 七种继承方法

目录 1. 第一种方法:原型链继承 2. 第二种方法:构造函数继承(call继承) 3. 第三种方法:组合式继承 4. 第四种方法:拷贝继承 5. 第五种方法:原型式继承 6. 第六种方法...

Unity Shader 实现X光效果

Unity Shader 实现X光效果 Unity Shader 实现实物遮挡外轮廓发光效果第五人格黎明杀机火炬之光 实现方案操作实现立体感优化总结源码 Unity Shader 实现实物遮挡外轮廓发光效果 之前看过《火炬之光》、《黎明杀机》、《第五人格》等不少的游戏里面人物被建筑物遮挡呈现出不同的…...

Android Camera相关类功能整理

1.Camera Java相关类 代码目录&#xff1a;frameworks/base/core/java/android/hardware/camera2/ CameraManager&#xff1a;camera系统服务管理类&#xff0c;用于监测、获取特征值和连接Camera设备。 CameraManager.CameraManagerGlobal:全局camera Manager实例&#xff…...

3、Git分支操作与团队协作

Git分支操作 1.什么是分支2. 分支的好处3. 分支的操作3.1 查看分支3.2 创建分支3.3 切换分支3.4 修改分支3.5 合并分支3.6 产生和解决冲突 4. 创建分支和切换分支图解5. Git团队协作机制团队内协作跨团队协作 均在git bash中进行操作。事先建好本地工作库 1.什么是分支 在版本…...

Linux网卡配置

一、网卡配置 1、目录参数 /etc/syscofig/network-scripts/ifcfg-e*** /etc 目录时Linux系统的配置文件&#xff0c;有相对权限的用户能修改目录&#xff0c;但普通用户都可以访问。 sysconfig /etc/sysyconfig目录包含了Linux的系统配置文件 network-scripts network-scripts…...

wireshark access/trunk/hybrid报文分析

1&#xff0c;access接口 发送带vlan的报文 wireshark交换机配置 [Huawei-GigabitEthernet0/0/1] [Huawei-GigabitEthernet0/0/1]port link-type access [Huawei-GigabitEthernet0/0/1]port default vlan 100 [Huawei-GigabitEthernet0/0/2]port link-type access [Huawei-Gig…...

C++ Primer Plus----第十二章--类和动态内存分布

本章内容包括&#xff1a;对类成员使用动态内存分配&#xff1b;隐式和显式复制构造函数&#xff1b;隐式和显式重载赋值运算符&#xff1b;在构造函数中使用new所必须完成的工作&#xff1b;使用静态类成员&#xff1b;将定位new运算符用于对象&#xff1b;使用指向对象的指针…...

清理 Oracle Arch 目录中的日志文件

清理Oracle Arch目录中的文件需要遵循以下步骤&#xff1a; 1、登陆Oracle数据库服务器&#xff1a;确保你有权限访问Oracle数据库服务器&#xff0c;并且能够登录到服务器操作系统。 ssh 192.168.1.200 su - oracle2、启动RMAN&#xff08;Recovery Manager&#xff09;&…...

PicGo+GitHub搭建免费图床

PicGoGitHub搭建免费图床 步骤 1: 安装 PicGo步骤 2:创建图床仓库步骤 3: 配置 GitHub Token步骤 4: 配置 PicGo步骤 5: 上传图片步骤 6: 访问图片 使用 GitHub 作为图床的优势在于免费、稳定且具有版本控制功能&#xff0c;特别适合个人博客、小型项目等。PicGo作为一个开源的…...

免费在线客服软件推荐:经济实用的客户沟通解决方案

好用的在线客服软件是企业是必不可少的工具&#xff0c;他让企业流程更流畅高效&#xff0c;让客户服务更完善优质。市场上的在线客服软件有很多&#xff0c;说着免费使用的软件也不在少数。今天小编就来推荐一款免费在线客服软件。 不过&#xff0c;我们选择免费在线客服软件…...

leetcode344. 反转字符串

题目描述 编写一个函数&#xff0c;其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。 不要给另外的数组分配额外的空间&#xff0c;你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。 示例 1&#xff1a; 输入&#xff1a;s ["h&quo…...

【js自定义鼠标样式】【js自定义鼠标动画】

文章目录 前言一、效果图二、实现步骤1. 去除原有鼠标样式2. 自定义鼠标样式3. 使用 总结 前言 自定义鼠标形状&#xff0c;自定义鼠标的动画&#xff0c;可以让我们的页面更加有设计感。 当前需求&#xff1a;吧鼠标自定义成一个正方形&#xff0c;鼠标的效果有&#xff1a;和…...

Linux开发工具——gdb篇

Linux下调试工具——gdb 文章目录 makefile自动化构建工具 gdb背景 gdb的使用 常用命令 总结 前言&#xff1a; 编写代码我们使用vim&#xff0c;编译代码我们使用gcc/g&#xff0c;但是我们&#xff0c;不能保证代码没问题&#xff0c;所以调试是必不可少的。与gcc/vim一样&…...

spring状态机

1、概述 Spring State Machine 是一个用于处理状态机逻辑的框架&#xff0c;它提供了一种简洁的方法来定义状 态、转换以及在状态变更时触发的动作。 概念 状态 &#xff08; State &#xff09; &#xff1a;一个状态机至少要包含两个状态。例如自动门的例子&#xff0c;有 …...

K8S异常处理

一、概述 1、k8s有时候会报错The connection to the server ip:6443 was refused - did you specify the right host or port &#xff0c;本文档提供几种可能产生该报错的原因和排障思路。 二、发现问题 使用任意Kubectl 命令会报错&#xff1a;The connection to the serv…...

【挑战全网最易懂】深度强化学习 --- 零基础指南

深度强化学习介绍、概念 强化学习介绍离散场景&#xff0c;使用行为价值方法连续场景&#xff0c;使用概率分布方法实时反馈连续场景&#xff1a;使用概率分布 行为价值方法 强化学习六要素设计奖励函数设计评论家策略学习与优化 算法路径深度 Q 网络 DQN演员-评论家算法&…...

做安防在哪个网站做广告呢/怎么做互联网营销推广

FYI:For Your Information.供您参考。 PFA:please find attached.请参看附件。...

b2c网站怎么做/宁波seo关键词培训

展开全部 顾名思义&#xff0c;缩进就是向里面收缩的意思&#xff0c;比如汉语书写习e68a8462616964757a686964616f31333363373039惯文章每段前面都要空两个字&#xff0c;这就叫首行缩进。段落缩进自然就是指整个段向内收缩了。 那么python语法缩进是什么意思呢&#xff1f; 学…...

和俄罗斯美女做的视频网站/百度公司招聘信息

展开全部计算机硬件由五妇部分构成&#xff1a;运算曝制奇储其入设备跟输掣。1、运算毗运算沏虱单元(ALU)、累加拼态寄存屁用寄存迫组成。算虱运算单元(ALU)的基本功能为加、妓、除四糟&#xff0c;与、磺、异贿辑操自及移位、侨操?p>计算机运行时&#xff0c;运算瀑踪奏由…...

做医院的系统网站怎么做/app开发需要多少钱

基于乐鑫ESP8266的SOC解决方案参考文章&#xff1a; &#xff08;1&#xff09;基于乐鑫ESP8266的SOC解决方案 &#xff08;2&#xff09;https://www.cnblogs.com/dapangsen/p/6392621.html &#xff08;3&#xff09;https://www.codeprj.com/blog/618b2d1.html 备忘一下…...

天长做网站的/2345网址导航删除办法

「2019 Python开发者日」全日程揭晓&#xff0c;请扫码咨询 ↑↑↑作者 | 伊凡伊德里斯&#xff08;Ivan Idris&#xff09;&#xff0c;曾是Java和数据库应用开发者&#xff0c;后专注于Python和数据分析领域&#xff0c;致力于编写干净、可测试的代码。他还是《Python Machin…...

西部数码 wordpress/专门用来查找网址的网站

一、前言 此系列随笔是针对《深入理解Java虚拟机:JVM高级特性与最佳实践 第2版》的总结 上一节&#xff0c;我们搭建好了java的开发环境&#xff0c;这一节&#xff0c;我们来看Java的技术体系 二、Java技术体系 1.按功能划分 如 果 仅 从 传 统 意 义 上 来 看&#xff0c; Su…...