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

【Linix-Day12-线程同步和线程安全】

线程同步 和 线程安全

线程同步

除了信号量和互斥锁(互斥锁和条件变量上次介绍过),还有两种方式同步

1.读写锁

当同时对一块内存读写时,会出现下列问题,故而引入读写锁

在这里插入图片描述

接口介绍:

1.int pthread_rwlock_init(pthread_rwlock_t *rwlock, pthread_rwlockattr_t *attr);

函数功能:初始化读写锁

rwlock :传入定义的读写锁地址

attr : 读写锁的属性,一般默认为 NULL

返回值:如果成功,函数应返回零

2.int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);

函数功能:加读锁,其他线程无法写入

rwlock :传入定义的读写锁地址

3.int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);

函数功能:加写锁,其他线程无法写入,读取

rwlock :传入定义的读写锁地址

4.int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

函数功能:解锁,允许读和写

rwlock :传入定义的读写锁地址

5.int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

函数功能:销毁读写锁

rwlock :传入定义的读写锁地址

测试代码:

main.c

include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>pthread_rwlock_t rwlock;void *fun1(void *arg)
{for (int i = 0; i < 30; ++i){pthread_rwlock_rdlock(&rwlock);printf("fun1 read start\n");sleep(1);printf("fun1 read end\n");pthread_rwlock_unlock(&rwlock);sleep(1);}
}
void *fun2(void *arg)
{for (int i = 0; i < 10; ++i){pthread_rwlock_rdlock(&rwlock);printf("fun2 read start\n");sleep(3);printf("fun2 read end\n");pthread_rwlock_unlock(&rwlock);sleep(1);}
}
void *fun3(void *arg)
{for (int i = 0; i < 10; ++i){pthread_rwlock_wrlock(&rwlock);printf("fun3 write start\n");sleep(3);printf("fun3 write end\n");pthread_rwlock_unlock(&rwlock);sleep(1);}
}
int main()
{pthread_t id[3];pthread_rwlock_init(&rwlock, NULL);pthread_create(&id[0], NULL, fun1, NULL);pthread_create(&id[0], NULL, fun2, NULL);pthread_create(&id[0], NULL, fun3, NULL);for (int i = 0; i < 3; ++i){pthread_join(id[i], NULL);}pthread_rwlock_destroy(&rwlock);exit(0);
}

运行结果图:

2.条件变量

条件变量提供了一种线程间的通知机制:当某个共享数据达到某个值的时候,唤醒等待
这个共享数据的线程。

接口介绍:

1. int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *attr);

函数功能:初始化条件变量

cond:定义的条件变量的地址

attr:条件变量的属性,一般默认为 NULL

2. int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);

函数功能:进入条件变量等待队列

cond:定义的条件变量的地址

mutex:定义的互斥锁的地址

3. int pthread_cond_signal(pthread_cond_t *cond);

函数功能: 唤醒单个线程

cond:定义的条件变量的地址

4. int pthread_cond_broadcast(pthread_cond_t *cond);

函数功能:唤醒所有等待的线程

cond:定义的条件变量的地址

5.int pthread_cond_destroy(pthread_cond_t *cond);

函数功能:摧毁条件变量

cond:定义的条件变量的地址

测试代码

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
pthread_cond_t cond;
pthread_mutex_t mutex;void *fun1(void *arg)
{char *s = (char *)arg;while (1){// 阻塞,被唤醒pthread_mutex_lock(&mutex);pthread_cond_wait(&cond, &mutex);pthread_mutex_unlock(&mutex);printf("fun1 read:%s\n", s);if (strncmp(s, "end", 3) == 0){break;}}
}
void *fun2(void *arg)
{char *s = (char *)arg;while (1){// 阻塞,被唤醒pthread_mutex_lock(&mutex);pthread_cond_wait(&cond, &mutex);pthread_mutex_unlock(&mutex);printf("fun2 read:%s\n", s);if (strncmp(s,"end",3) == 0){break;}}
}int main()
{pthread_cond_init(&cond, NULL);pthread_mutex_init(&mutex, NULL);pthread_t id[2];char buff[256]={0};pthread_create(&id[0], NULL, fun1, (void*)buff);pthread_create(&id[1], NULL, fun2, (void*)buff);while(1){printf("input: ");fflush(stdout);fgets(buff,255,stdin);printf("\n");if(strncmp(buff,"end",3) == 0){pthread_cond_broadcast(&cond);break;}else{pthread_cond_signal(&cond);}sleep(1);}for(int i=0;i<2;++i){pthread_join(id[i],NULL);}pthread_mutex_destroy(&mutex);pthread_cond_destroy(&cond);exit(0);
}

运行结果图

在这里插入图片描述

线程安全

在多线程运行的时候,不论线程的调度顺序怎样,最终的结果都是一样的、正确的。那么就说这些线程是安全的。
要保证线程安全需要做到:
1)对线程同步,保证同一时刻只有一个线程访问临界资源。
2)在多线程中使用线程安全的函数(可重入函数),所谓线程安全的函数指的是:如果一个函数能被多个线程同时调用且不发生竟态条件,则我们程它是线程安全的。

下面展示使用不安全的线程函数举例

实现在两个线程中分别打印 char buff[] = “a b c d e f g h i”; char buff[] = “1 2 3 4 5 6 7 8 9”;两个数组

测试代码

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>void *PthreadFun(void *arg)
{char buff[] = "a b c d e f g h i";char *p = strtok(buff, " ");while (p != NULL){printf("fun:: %c\n", *p);p = strtok(NULL, " ");sleep(1);}
}int main()
{pthread_t id;int res = pthread_create(&id, NULL, PthreadFun, NULL);assert(res == 0);char buff[] = "1 2 3 4 5 6 7 8 9";char *p = strtok(buff, " ");while (p != NULL){printf("main:: %c\n", *p);p = strtok(NULL, " ");sleep(1);}exit(0);
}

运行结果

这是因为strtok()是线程不安全函数,内部实现使用了全局变量或静态变量,所以不能同时处理不同的字符串。

解决方法,使用线程安全版的 strtok_r();

char *strtok_r(char *str, const char *delim, char **saveptr);

str : 数组

delim: 分隔符

saveptr:是指向char*变量的指针,用来维护连续解析相同字符串的调用

代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>void *PthreadFun(void *arg)
{char *q = NULL;char buff[] = "a b c d e f g h i";char *p = strtok_r(buff, " ",&q);while (p != NULL){printf("fun:: %c\n", *p);p = strtok_r(NULL, " ",&q);sleep(1);}
}int main()
{pthread_t id;int res = pthread_create(&id, NULL, PthreadFun, NULL);assert(res == 0);char *q = NULL;char buff[] = "1 2 3 4 5 6 7 8 9";char *p = strtok_r(buff, " ",&q);while (p != NULL){printf("main:: %c\n", *p);p = strtok_r(NULL, " ",&q);sleep(1);}exit(0);
}

运行结果

相关文章:

【Linix-Day12-线程同步和线程安全】

线程同步 和 线程安全 线程同步 除了信号量和互斥锁&#xff08;互斥锁和条件变量上次介绍过&#xff09;&#xff0c;还有两种方式同步 1.读写锁 当同时对一块内存读写时&#xff0c;会出现下列问题&#xff0c;故而引入读写锁 接口介绍&#xff1a; 1.int pthread_rwloc…...

C++中使用嵌套循环遍历多维数组

C中使用嵌套循环遍历多维数组 一维数组&#xff1a;数组元素可以看做是一行数据。 二维数组&#xff1a;更像是一个表格&#xff0c;既有行数据又有列数据。 C没有提供二维数组类型&#xff0c;但用户可以创建每个元素本身都是数组的数组。例如&#xff0c;假设要存储 5 个城…...

linux入门---命名管道

如何创建命名管道 使用mkfifo函数就可以在程序里面创建管道文件&#xff0c;该函数的声明如下&#xff1a; 该函数需要两个参数&#xff0c;第一个参数表示要在哪个路径下创建管道文件并且这个路径得待上管道文件的名字&#xff0c;因为每个文件都有对应的权限&#xff0c;所…...

SpringBoot2.0入门(详细文档)

文章目录 Springboot是什么Springboot2.x依赖环境和版本新特性说明为什么学习Springboot从springboot优点来看从未来发展的趋势来看 开发环境Spring Boot开发环境搭建和项目启动jdk 的配置Spring Boot 工程的构建maven配置IDEA 快速构建maven 创建工程常用注解 完整代码 Spring…...

Aztec的隐私抽象:在尊重EVM合约开发习惯的情况下实现智能合约隐私

1. 引言 Aztec的架构&#xff0c;不同于当前“通过EVM兼容执行环境”所实现的区块链水平扩容趋势。Aztec内部笑称其构建的为首个非zkEVM协议。 Aztec专注于实现&#xff1a; 成为理解和需要智能合约隐私的开发者的终极解决方案。 Aztec为开发者提供构建隐私优先app所需的网…...

【Vue】详细介绍Vue项目的目录结构及各个核心文件的示例代码

Vue.js并没有严格的文件和目录结构要求&#xff0c;但一般情况下&#xff0c;我们的Vue项目目录结构如下&#xff1a; ├── node_modules/ # 项目依赖的 node 模块 ├── public/ # 公共资源目录 │ ├── favicon.ico # 网页图标 │ └──…...

【人大金仓】迁移MySql数据库到人大金仓,出现sys_config表重复

需要迁移的数据库中有张表名称为sys_config&#xff0c;查询的时候查询结果不符合我们的预期&#xff0c;经咨询金仓售后人员后得知和系统表重名… 解决问题方法如下&#xff1a; alter database [数据库名] set search_path to "$user", [模式名,&#xff08;可选&…...

linux内核进程间通信IPC----消息队列

消息队列&#xff1a;提供一种从一个进程向另一个进程发送一个数据块的方法。与FIFO相比&#xff0c;消息队列的优势在于&#xff0c;它独立于发送和接收进程而存在。 1.链表式结构组织&#xff0c;存放于内核。 2.通过队列标识来引用。 3.通过一个数据类型来索引指定的数据。 …...

PHP实现微信小程序状态检测(违规、暂停服务、维护中、正在修复)

实现原理 进入那些状态不正常的小程序会被重定向至一个Url&#xff0c;使用抓包软件抓取这个Url&#xff0c;剔除不必要参数&#xff0c;使用cURl函数请求网页获得HTML内容&#xff0c;根据内容解析出当前APPID的小程序的状态。 代码 <?php// 编码header(Content-type:ap…...

ubuntu在线直接升级

前几天VMware上安装了ubuntu&#xff0c;当时的内核版本支持(ipguard,加密软件)&#xff0c;后来ubuntu自动升级了linux内核&#xff0c;导致加入软件不支持&#xff0c;无法访问加密文件了。后来加密软件商更新了软件&#xff0c;但还是赶不上linux内核更新速度&#xff0c;还…...

学习笔记:卸载nav2 navigation2导航

nav2二进制文件安装 nav2导航安装方式分为二进制文件安装和源码方式安装&#xff0c;如果想用最快的方式跑通代码&#xff0c;推荐二进制安装&#xff0c;不用编译&#xff0c;没有缺少依赖编译失败的烦恼&#xff0c; 安装命令&#xff1a; sudo apt install ros-$ROS_DISTR…...

觉非科技数据闭环系列 | BEV感知研发实践

随着自动驾驶迈向量产场景&#xff0c;“BEV感知数据闭环”已成为新一代自动驾驶量产系统的核心架构。数据成为了至关重要的技术驱动力&#xff0c;发挥数据闭环的飞轮效应或将成为下半场从1到N的胜负关键。 觉非科技在此方面已进行了大量的研究工作&#xff0c;并在实际量产项…...

程序员情绪把控

文章目录 建议情绪 建议 保持稳定的情绪在工作中非常重要&#xff0c;以下是一些建议&#xff1a; 自我意识&#xff1a;保持对自己情绪的觉察和理解&#xff0c;了解自己的情绪状态和触发情绪的因素。通过自我反省和观察&#xff0c;你可以更好地管理和调节情绪。 健康生活方…...

弱监督目标检测:ALWOD: Active Learning for Weakly-Supervised Object Detection

论文作者&#xff1a;Yuting Wang,Velibor Ilic,Jiatong Li,Branislav Kisacanin,Vladimir Pavlovic 作者单位&#xff1a;Rutgers University;The Institute for Artificial Intelligence Research and Development of Serbia;Nvidia Corporation 论文链接&#xff1a;http:…...

驱动开发 day3

总结&#xff1a;自动创建设备节点udev的流程 1.如何创建节点 手动创建&#xff1a;mknod 地址 设备文件类型 主设备号 次设备号(0 - 255) 自动创建&#xff1a;devfs (创建节点的逻辑在内核 ---> 2.4版本以前使用) udev (创建节点的逻辑在应用层) mdev (轻量级的udev) 2.…...

许可license分析 第一章

许可分析是指对软件许可证进行详细的分析和评估&#xff0c;以了解组织内部对软件许可的需求和使用情况。通过许可分析&#xff0c;可以帮助组织更好地管理和优化软件许可证的使用。以下是一些可能的许可分析方法和步骤&#xff1a; 收集许可证信息&#xff1a;首先&#xff0c…...

Goby 漏洞发布|管家婆订货易在线商城 SelectImage.aspx 文件上传漏洞

漏洞名称&#xff1a;管家婆订货易在线商城 SelectImage.aspx 文件上传漏洞 English Name&#xff1a; GJP SelectImage.aspx file upload vulnerability CVSS core: 9.8 影响资产数&#xff1a;2617 漏洞描述&#xff1a; 任我行率先针对中小企业推出了管家婆进销存、财务…...

Android屏幕录制

这里使用Java语言编写实现&#xff0c;完整代码如下&#xff1a; 文件 AndroidMainfest.xml 的主要配置 <?xml version"1.0" encoding"utf-8"?> <manifest xmlns:android"http://schemas.android.com/apk/res/android"package"…...

实在智能牵手埃林哲,“TARS-RPA-Agent+云时通”双剑合璧共推企业数字化转型

近日&#xff0c;《数字中国建设整体布局规划》进一步明确了数字化发展的方向和节奏&#xff0c;对企业数字化建设提出了新要求。回看过去几十年&#xff0c;信息化建设如火如荼&#xff0c;各类IT系统如雨后春笋般涌现&#xff0c;系统的自动化操作及系统间数据交互共享等需求…...

拥有这个中文版CustomGPT,你也能定制自己的AI问答机器人

人工智能技术的快速发展为各行各业带来了前所未有的机会&#xff0c;其中之一就是定制化的问答机器人。这些机器人可以用于客户支持、知识管理、虚拟助手等多个领域&#xff0c;帮助企业提高效率&#xff0c;提供更好的用户体验。很多人可能都知道通过CustomGPT能够设计自己的人…...

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展&#xff1a;显示创建时间8. 功能扩展&#xff1a;记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

.Net框架,除了EF还有很多很多......

文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

Java多线程实现之Callable接口深度解析

Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

初学 pytest 记录

安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

Java数值运算常见陷阱与规避方法

整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...

宇树科技,改名了!

提到国内具身智能和机器人领域的代表企业&#xff0c;那宇树科技&#xff08;Unitree&#xff09;必须名列其榜。 最近&#xff0c;宇树科技的一项新变动消息在业界引发了不少关注和讨论&#xff0c;即&#xff1a; 宇树向其合作伙伴发布了一封公司名称变更函称&#xff0c;因…...

MySQL 部分重点知识篇

一、数据库对象 1. 主键 定义 &#xff1a;主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 &#xff1a;确保数据的完整性&#xff0c;便于数据的查询和管理。 示例 &#xff1a;在学生信息表中&#xff0c;学号可以作为主键&#xff…...

破解路内监管盲区:免布线低位视频桩重塑停车管理新标准

城市路内停车管理常因行道树遮挡、高位设备盲区等问题&#xff0c;导致车牌识别率低、逃费率高&#xff0c;传统模式在复杂路段束手无策。免布线低位视频桩凭借超低视角部署与智能算法&#xff0c;正成为破局关键。该设备安装于车位侧方0.5-0.7米高度&#xff0c;直接规避树枝遮…...

离线语音识别方案分析

随着人工智能技术的不断发展&#xff0c;语音识别技术也得到了广泛的应用&#xff0c;从智能家居到车载系统&#xff0c;语音识别正在改变我们与设备的交互方式。尤其是离线语音识别&#xff0c;由于其在没有网络连接的情况下仍然能提供稳定、准确的语音处理能力&#xff0c;广…...