Linux:线程同步与互斥

目录

线程互斥

初始化 

销毁

加锁

解锁 

线程同步

条件变量

初始化

销毁

等待条件满足

唤醒等待

pthread_cond_signal

pthread_cond_broadcast

生产者消费者模型

3种关系

2种角色

1个交易场所 

POSIX信号量

初始化

销毁

等待

发布


线程互斥

互斥相关概念

临界资源:多线程执行流共享的资源就叫做临界资源。 

临界区:每个线程内部,访问临界资源的代码,就叫做临界区。

互斥:任何时刻,互斥保证有且只有一个执行流进入临界区,访问临界资源,通常对临界资源起保护作用。

原子性:不会被任何调度机制打断的操作,该操作只有两态,要么完成,要么未完成。


多线程并发操作一些共享变量会有一些问题

例如变量++,--的操作就不能多线程并发访问

++,--的操作在汇编中需要分为3步

1.将变量从内存加载到寄存器中

2.更新寄存器里面的值,执行+1(-1)操作

3.将新值从寄存器写回会变量的内存地址中

因为寄存器用的都是同一个,在并发访问时就会出现问题

要解决以上问题,需要做到三点:

1.代码必须要有互斥行为:当代码进入临界区执行时,不允许其他线程进入该临界区。 

2.如果多个线程同时要求执行临界区的代码,并且临界区没有线程在执行,那么只能允许一个线程进入该临界区。

3.如果线程不在临界区中执行,那么该线程不能阻止其他线程进入临界区。

想要做到这三点,我们可以使用一把锁。Linux上提供的这把锁叫互斥量 

pthread_mutex_t 

这是一个互斥锁的类型,定义在POSIX线程库中。

互斥锁用于保护共享资源的访问,确保在多线程环境中,同一时间只有一个线程可以访问该资源,从而避免数据竞争和不一致的问题。

我们可以用这个类型来定义一个锁变量,并初始化它

初始化 

方法1:

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER 

PTHREAD_MUTEX_INITIALIZER这是一个宏,用于初始化静态分配的互斥锁

方法2:

#include <pthread.h>int pthread_mutex_init(pthread_mutex_t *mutex, 
const pthread_mutexattr_t *mutexattr);

mutex:指向要初始化的互斥锁对象的指针

mutexattr:指向互斥锁属性对象的指针。如果为NULL,则使用默认属性(一般情况使用NULL即可)

返回值:

成功:返回0 

失败:返回错误码

销毁

锁也需要像malloc,new出来的动态内存一样需要我们手动释放,但并不是所有情况都需要手动释放的

当使用PTHREAD_MUTEX_INITIALIZER初始化的互斥量不需要销毁

#include <pthread.h>int pthread_mutex_destroy(pthread_mutex_t *mutex);

mutex:指向要销毁的互斥锁对象的指针

返回值:

成功:返回0 

失败:返回错误码

加锁

我们可以对一段代码区进行加锁,这样就只能有单执行流访问一段代码了

#include <pthread.h>int pthread_mutex_lock(pthread_mutex_t *mutex);

pthread_mutex_lock用于锁定一个互斥锁

mutex:指向要锁定的互斥锁对象的指针

返回值:

成功:返回0 

失败:返回错误码

解锁 

有加锁当然也会有解锁,加锁和解锁之间的区域就是我们拥有锁的区域

#include <pthread.h>int pthread_mutex_unlock(pthread_mutex_t *mutex);

pthread_mutex_unlock用于解锁一个互斥锁

mutex:指向要解锁的互斥锁对象的指针

返回值:

成功:返回0 

失败:返回错误码

线程同步

条件变量

条件变量是一种在多线程编程中用于线程同步的机制,它允许线程在某些条件不满足时进入等待状态,直到条件满足时才被唤醒继续执行。 

初始化

初始化一个条件变量。

int pthread_cond_init(pthread_cond_t *cond
, const pthread_condattr_t *cond_attr);

cond:指向条件变量的指针,需要初始化的条件变量。

cond_attr: 指向条件变量属性的指针。如果为NULL,则使用默认属性。

返回值:

成功:返回0 

失败:返回错误码

销毁

销毁一个条件变量,释放相关资源。 

int pthread_cond_destroy(pthread_cond_t *cond);

 cond:指向条件变量的指针,需要销毁的条件变量。

返回值:

成功:返回0 

失败:返回错误码

等待条件满足

使线程进入等待状态,直到条件变量被通知。 

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

cond:指向条件变量的指针。

mutex:指向互斥锁的指针,该互斥锁必须已经被当前线程锁定。

当调用pthread_cond_wait的时候,线程会释放mutex,并进入等待状态

当条件变量被通知时,线程会被唤醒,并重新尝试获取mutex

唤醒等待

pthread_cond_signal

通知一个等待条件变量的线程。

int pthread_cond_signal(pthread_cond_t *cond);

cond:指向条件变量的指针。

返回值:

成功:返回0 

失败:返回错误码

pthread_cond_broadcast

通知所有等待条件变量的线程。

int pthread_cond_broadcast(pthread_cond_t *cond);

cond:指向条件变量的指针。

返回值:

成功:返回0 

失败:返回错误码

生产者消费者模型

3种关系

生产者之间:竞争关系,互斥关系

消费者之间:竞争关系,互斥关系

生产者和消费者之间:竞争关系,互斥关系,同步关系

2种角色

生产者角色和消费者角色

1个交易场所 

以特定结构构成的内存空间

POSIX信号量

初始化

初始化一个信号量。

#include <semaphore.h>int sem_init(sem_t *sem, int pshared, unsigned int value);

sem:指向信号量的指针。

pshared:指定信号量是否可以在不同进程之间共享。为0:信号量仅在当前进程内的线程之间共享。非0:信号量可以在不同进程之间共享(需要映射到共享内存)

value:信号量的初始值。

返回值:

成功:返回0 

失败:返回错误码

销毁

销毁一个信号量,释放相关资源。 

#include <semaphore.h>int sem_destroy(sem_t *sem);

sem:指向信号量的指针。

返回值:

成功:返回0 

失败:返回错误码

等待

使线程进入等待状态,直到信号量的值大于零,然后将信号量的值减一。

#include <semaphore.h>int sem_wait(sem_t *sem);

sem:指向信号量的指针。

返回值:

成功:返回0 

失败:返回错误码

发布

将信号量的值加一,通知等待信号量的线程。

#include <semaphore.h>int sem_post(sem_t *sem);

sem:指向信号量的指针。

返回值:

成功:返回0 

失败:返回错误码


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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode --- 448 周赛

题目列表 3536. 两个数字的最大乘积 3537. 填充特殊网格 3538. 合并得到最小旅行时间 3539. 魔法序列的数组乘积之和 一、两个数字的最大乘积 由于数据都是正数&#xff0c;所以乘积最大的两个数&#xff0c;本质就是找数组中最大的两个数即可&#xff0c;可以排序后直接找到…

Azure Document Intelligence

Azure Document Intelligence(以前称为 Form Recognizer)是一项云服务&#xff0c;可用于从文档中提取文本、键值对、表等信息。下面是一个使用 Python SDK 进行文档转换和提取信息的基本示例。 1. 安装依赖 首先&#xff0c;你需要安装 azure-ai-formrecognizer 库&#xff0c…

51单片机快速成长路径

作为在嵌入式领域深耕18年的工程师&#xff0c;分享一条经过工业验证的51单片机快速成长路径&#xff0c;全程干货无注水&#xff1a; 一、突破认知误区&#xff08;新手必看&#xff09; 不要纠结于「汇编还是C」&#xff1a;现代开发90%场景用C&#xff0c;掌握指针和内存管…

SQLite数据库加密(Java语言、python语言)

1. 背景与需求 SQLite 是一种轻量级的关系型数据库,广泛应用于嵌入式设备、移动应用、桌面应用等场景。为了保护数据的隐私与安全,SQLite 提供了加密功能(通过 SQLCipher 扩展)。在 Java 中,可以使用 sqlite-jdbc 驱动与 SQLCipher 集成来实现 SQLite 数据库的加密。 本…

《AI大模型应知应会100篇》第53篇:Hugging Face生态系统入门

第53篇&#xff1a;Hugging Face生态系统入门 ——从模型获取到部署的全流程实战指南 &#x1f4cc; 摘要 在人工智能快速发展的今天&#xff0c;Hugging Face已成为自然语言处理&#xff08;NLP&#xff09;领域最具影响力的开源平台之一。它不仅提供丰富的预训练模型、强大…

什么是向量数据库?向量数据库和关系数据库有什么区别?

什么是向量数据库&#xff1f; 向量数据库是一种专门设计用来存储、索引和查询向量数据的数据库系统。在当今的人工智能和机器学习领域中&#xff0c;向量数据库变得越来越重要&#xff0c;尤其是在处理高维数据如图像、音频和文本等非结构化数据时。 主要用途 相似度搜索&…

关于甲骨文(oracle cloud)丢失MFA的解决方案

前两年&#xff0c;申请了一个招商的多币种信用卡&#xff0c;然后就从网上撸了一个oracle的免费1h1g的服务器。 用了一段时间&#xff0c;人家要启用MFA验证。 啥叫MFA验证&#xff0c;类似与短信验证吧&#xff0c;就是绑定一个手机&#xff0c;然后下载一个app&#xff0c;每…

基于Arduino Nano的DIY示波器

基于Arduino Nano的DIY示波器&#xff1a;打造属于你的口袋实验室 前言 在电子爱好者的世界里&#xff0c;示波器是不可或缺的工具之一。它能够帮助我们观察和分析各种电子信号的波形&#xff0c;从而更好地理解和调试电路。然而&#xff0c;市面上的示波器价格往往较高&…

LeetCode 解题思路 47(最长回文子串、最长公共子序列)

解题思路&#xff1a; dp 数组的含义&#xff1a; dp[i][j] 是否为回文子串。递推公式&#xff1a; dp[i][j] s.charAt(i) s.charAt(j) && dp[i 1][j - 1]。dp 数组初始化&#xff1a; 单字符 dp[i][i] true&#xff0c;双字符 dp[i][i 1] s.charAt(i) s.charA…

通过管道实现C++ Linux独立进程之间的通信和字符串传递

在Linux环境下&#xff0c;独立进程之间的通信&#xff08;IPC&#xff09;可以通过多种方式实现&#xff0c;包括管道、消息队列、共享内存和套接字。本文将详细介绍如何使用管道&#xff08;pipe&#xff09;在C中实现独立进程之间的通信&#xff0c;并传递字符串。 一、管道…

神经网络极简入门技术分享

1. 引言 神经网络是深度学习的基础&#xff0c;其设计灵感来源于人脑神经元的结构和工作方式。尽管现代神经网络已经变得异常复杂&#xff0c;但其核心原理却相对简单易懂。本报告旨在通过剖析神经网络的最基本单元——神经元&#xff0c;帮助初学者理解神经网络的工作原理。 …

五、Hadoop集群部署:从零搭建三节点Hadoop环境(保姆级教程)

作者&#xff1a;IvanCodes 日期&#xff1a;2025年5月7日 专栏&#xff1a;Hadoop教程 前言&#xff1a; 想玩转大数据&#xff0c;Hadoop集群是绕不开的一道坎。很多小伙伴一看到集群部署就头大&#xff0c;各种配置、各种坑。别慌&#xff01;这篇教程就是你的“救生圈”。 …

科研项目管理:4款高效工具推荐与效率提升实践

一般来说&#xff0c;科研项目往往涉及复杂的任务、跨部门协作以及严格的时间和预算限制。传统的管理方式&#xff0c;如电子表格或邮件沟通&#xff0c;难以应对多任务并行、资源分配复杂的需求。借助现代项目管理工具&#xff0c;研究人员能够优化工作流程、提升团队协作效率…

如何统一修改word中所有英文字母的字体格式

1.需求分析 我想让整篇论文中的所有英文字母格式都修改为Time New Roman格式。 2.直观操作流程 点击左上角开始 --> 点击替换 --> 点击更多 --> 点击特殊格式 --> 选择查找内容为任意字母(Y) --> 将光标点到替换内容 --> 点击格式 --> 点击字体 --> …

【疑难杂症2025-003】Java-mvn项目在gitlab-ci构建镜像时遇到的问题和解决方案

本文由Markdown语法编辑器编辑完成&#xff0e; 1.背景: 之前从同事手里接手了一个java的项目&#xff0c;是用maven构建项目的&#xff0e;由于我们的服务都是基于docker来部署的&#xff0c;因此这个java项目也是要编译成docker image然后发布&#xff0e;但是之前一直都是…

【RT-Thread Studio】nor flash配置Fal分区

前置条件&#xff1a;【RT-Thread Studio】W25Q128配置 添加 FAL软件包 配置SFUD驱动程序&#xff0c;使用FAL的设备为W25Q128 将fal_cfg.h和fal_flash_sfud_port.c提取出来&#xff0c;放到自己创建的fal_porting目录。 修改 fal_flash_sfud_port.c struct fal_flash_dev n…

Spring MVC 视图解析器 (ViewResolver) 如何配置? Spring Boot 是如何自动配置常见视图解析器的?

我们来详细分析一下视图解析器 (ViewResolver) 的配置以及 Spring Boot 是如何自动配置它们的。 视图解析器 (ViewResolver) 是什么&#xff1f; 在 Spring MVC 中&#xff0c;当控制器 (Controller) 方法处理完请求并返回一个逻辑视图名 (String) 时&#xff0c;DispatcherS…

理解网站导航文件:robots.txt、sitemap.xml与LLMs.txt的全面解析

在当今数字化时代&#xff0c;网站不仅需要为人类用户提供良好的浏览体验&#xff0c;还需要考虑搜索引擎和人工智能系统的可访问性。本文将深入探讨三种关键的网站导航文件&#xff1a;传统的robots.txt和sitemap.xml&#xff0c;以及新兴的LLMs.txt&#xff0c;分析它们的功能…

leetcode 349. Intersection of Two Arrays

题目描述 题目限制0 < nums1[i], nums2[i] < 1000&#xff0c;所以可以开辟一个1001个元素的数组来做哈希表。 class Solution { public:vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {vector<int> table(1001,0…

【软件工程】软件多缺陷定位方法总结

软件多缺陷定位(Multi-Fault Localization)是软件工程中的一个重要研究方向,旨在同时定位代码中存在的多个缺陷(Bug)。由于多个缺陷可能相互干扰(如掩盖错误行为),导致传统单缺陷定位方法效果下降,因此需要针对多缺陷场景的特殊性设计方法。以下是常见的多缺陷定位方法…