linux----------------------线程同步与互斥(上)

1.线程互斥

1-1 进程线程间的互斥相关背景概念

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

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

互斥:任何时刻,互斥保证只有一个执行进入临界区,对临界资源起到保护作用

原子性:不会被任何调度打断的操作,只有两种状态一个是完成一个是未完成

1-2互斥量mutex

大部分情况线程使用的数据都是局部变量,变量的地址存放在线程栈空间里面,这种情况,变量归属单个线程,其他线程无法获得该变量。有的时候多个线程需要对同一个变量进行操作找个变量称为共享变量,多个线程并发的操作共享变量会带来一些问题

// 操作共享变量会有问题的售票系统代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
int ticket = 100;void *route(void *arg)
{
char *id = (char*)arg;
while ( 1 ) {
if ( ticket > 0 ) {
usleep(1000);
printf("%s sells ticket:%d\n", id, ticket);
ticket--;} 
else {break;}
}
}
int main( void )
{pthread_t t1, t2, t3, t4;pthread_create(&t1, NULL, route, "thread 1");pthread_create(&t2, NULL, route, "thread 2");pthread_create(&t3, NULL, route, "thread 3");pthread_create(&t4, NULL, route, "thread 4");pthread_join(t1, NULL);pthread_join(t2, NULL);pthread_join(t3, NULL);pthread_join(t4, NULL);
}
⼀次执⾏结果:
thread 4 sells ticket:100
...
thread 4 sells ticket:1
thread 2 sells ticket:0
thread 1 sells ticket:-1
thread 3 sells ticket:-2

为什么只有100张票到0了的时候还有票能售出去呢?

这就是线程并发执行处理共享数据带来的问题,在我处理最后一张票的时候其他线程也进来了他们看到的都是1此时他们还不知道这个票已经被其他线程给执行完了。如何解决这个问题呢?

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

如果多个线程同时要求执⾏临界区的代码,并且临界区没有线程在执⾏,那么只能允许⼀个线程
进⼊该临界区。
如果线程不在临界区中执⾏,那么该线程不能阻⽌其他线程进⼊临界区。
要做到这三点只需要在临界区资源上一把锁。linux上提供的这把锁就叫做互斥量

互斥量的接口

初始化互斥量有两种第

1 静态分配

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER
2 动态分配
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const
pthread_mutexattr_t *restrict attr);
参数:
mutex:要初始化的互斥量
attrNULL
销毁互斥量
销毁互斥量需要注意
使⽤ PTHREAD_ MUTEX_ INITIALIZER 初始化的互斥量不需要销毁
不要销毁⼀个已经加锁的互斥量
已经销毁的互斥量,要确保后⾯不会有线程再尝试加锁
int pthread_mutex_destroy(pthread_mutex_t *mutex);

互斥量加锁和解锁

int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
返回值:成功返回0,失败返回错误号

调用 pthread_lock是,可能会遇到以下情况

互斥量处于未上锁状态,该函数会讲把互斥量锁定返回成功

如何发起函数调用时,其他线程已锁定互斥量,没有竞争到互斥量资源,此时pthread_lock调用会陷入阻塞,直到互斥量解锁

修该上面的售票代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sched.h>
int ticket = 100;
pthread_mutex_t mutex;
void *route(void *arg)
{
char *id = (char*)arg;
while ( 1 ) {
pthread_mutex_lock(&mutex);if ( ticket > 0 ) {
usleep(1000);
printf("%s sells ticket:%d\n", id, ticket);
ticket--;
pthread_mutex_unlock(&mutex);
// sched_yield(); 放弃CPU
} 
else {
pthread_mutex_unlock(&mutex);
break;
}}}int main( void )
{
pthread_t t1, t2, t3, t4;
pthread_mutex_init(&mutex, NULL);
pthread_create(&t1, NULL, route, "thread 1");
pthread_create(&t2, NULL, route, "thread 2");
pthread_create(&t3, NULL, route, "thread 3");
pthread_create(&t4, NULL, route, "thread 4");
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_join(t3, NULL);
pthread_join(t4, NULL);
pthread_mutex_destroy(&mutex);
}

1-3 互斥量的封装

test_4_22_httpserve/Mutex.h · liu xi peng/linux---ubuntu系统 - 码云 - 开源中国

大家有兴趣的可以点进去看一下

2.线程同步

2-1 条件变量

当一个线程互斥地访问某个变量时,他可能发现在其他线程状态改变之前他什么也做不了

例如⼀个线程访问队列时,发现队列为空,它只能等待,只到其它线程将⼀个节点添加到队列

中。这种情况就需要⽤到条件变量。

2-2 同步概念与竞态条件

同步:在保证数据安全的前提下,让线程能够按照某种特定的顺序访问临界资源,从⽽有效避免
饥饿问题,叫做同步
竞态条件:因为时序问题,⽽导致程序异常,我们称之为竞态条件。在线程场景下,这种问题也
不难理解

2-3 条件变量函数

初始化

int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t
*restrict attr);
参数:
cond:要初始化的条件变量
attrNULL
销毁
1 int pthread_cond_destroy(pthread_cond_t *cond)
等待条件满⾜
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict
mutex);
参数:
cond:要在这个条件变量上等待
mutex:互斥量,后⾯详细解释
唤醒等待
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
#include <iostream>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *active( void *arg )
{
std::string name = static_cast<const char*>(arg);
while (true){
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
std::cout << name << " 活动..." << std::endl;
pthread_mutex_unlock(&mutex);
}
}
int main( void )
{
pthread_t t1, t2;
pthread_create(&t1, NULL, active, (void*)"thread-1");
pthread_create(&t2, NULL, active, (void*)"thread-2");
sleep(3); // 可有可⽆,这⾥确保两个线程已经在运⾏
while(true)
{
// 对⽐测试
// pthread_cond_signal(&cond); // 唤醒⼀个线程
pthread_cond_broadcast(&cond); // 唤醒所有线程
sleep(1);
}pthread_join(t1, NULL);
pthread_join(t2, NULL);
}

运行结果:

thread-1 活动...
thread-2 活动...
thread-1 活动...
thread-1 活动...
thread-2 活动...
2-4 ⽣产者消费者模型
321原则(便于记忆)
产消费模型是一种多线程并发的生产模型他有三种关系分别是消费者对消费者,生产者对生产者,消费着对生产者,分别是互斥,互斥,互斥和同步关系
由线程来承担消费者和生产者,线程可有多个,通常有一个特定的数据结构提供的缓冲区这个缓存区通常被成为交易场所

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

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

相关文章

百度AI的开放新篇章:文心4.5本地化部署指南与未来生态战略展望

百度AI的开放新篇章&#xff1a;文心4.5本地化部署指南与未来生态战略展望 一起来玩转文心大模型吧&#x1f449;文心大模型免费下载地址&#xff1a;https://ai.gitcode.com/theme/1939325484087291906 &#x1f31f; 嗨&#xff0c;我是IRpickstars&#xff01; &#x1f30…

笔记/sklearn中的数据划分方法

文章目录一、前言二、数据划分方法1. 留出法&#xff08;Hold-out&#xff09;2. K折交叉验证&#xff08;K-Fold&#xff09;3. 留一法&#xff08;Leave-One-Out&#xff09;三、总结一、前言 简要介绍数据划分在机器学习中的作用。 二、数据划分方法 1. 留出法&#xff0…

Android14 开屏页SplashScreen设置icon圆角的原理

简介 我们在看到一个应用在启动的时候会看到一个启动的icon,这个图标是应用的icon当然也是可以应用自己去控制的如 <item name="android:windowSplashScreenAnimatedIcon">@drawable/adas_icon</item> 图上的效果明显不理想,图标是自带圆角,而且还是…

flutter redux状态管理

&#x1f4da; Flutter 状态管理系列文章目录 Flutter 状态管理(setState、InheritedWidget、 Provider 、Riverpod、 BLoC / Cubit、 GetX 、MobX 、Redux) setState() 使用详解&#xff1a;原理及注意事项 InheritedWidget 组件使用及原理 Flutter 中 Provider 的使用、注…

AMIS全栈低代码开发

amis是百度开源的前端低代码框架&#xff0c;它通过JSON配置来生成各种后台页面&#xff0c;旨在简化前端开发过程&#xff0c;提高开发效率&#xff0c;降低开发门槛。以下是详细介绍&#xff1a; 核心特点&#xff1a; 可视化开发&#xff1a;允许开发者通过可视化方式构建页…

【Python基础】变量、运算与内存管理全解析

一、删除变量与垃圾回收&#xff1a;内存管理的底层逻辑 在Python中&#xff0c;变量是对象的引用&#xff0c;而不是对象本身。当我们不再需要某个变量时&#xff0c;可以用del语句删除它的引用&#xff0c;让垃圾回收机制&#xff08;GC&#xff09;自动清理无引用的对象。 1…

Spring Boot + Javacv-platform:解锁音视频处理的多元场景

Spring Boot Javacv-platform&#xff1a;解锁音视频处理的多元场景 一、引言 在当今数字化时代&#xff0c;音视频处理已成为众多应用场景中不可或缺的一部分&#xff0c;从在线教育、视频会议到短视频平台、智能安防等&#xff0c;音视频数据的处理与分析需求日益增长。Java…

k8s 的基本原理、架构图、使用步骤和注意事项

Kubernetes&#xff08;k8s&#xff09;是一个开源的容器编排平台&#xff0c;用于自动化部署、扩展和管理容器化应用。以下是其基本原理、使用步骤和注意事项的总结&#xff1a;一、k8s 基本原理核心架构 Master 节点&#xff1a;控制集群的核心组件&#xff0c;包括&#xff…

Qt 多线程编程:单例任务队列的设计与实现

引言&#xff1a; 在现代应用程序开发中&#xff0c;多线程编程已成为处理异步任务的标配。对于 GUI 应用而言&#xff0c;保持主线程的响应性尤为重要。本文将详细介绍一个基于 Qt 的单例任务队列实现方案&#xff0c;它通过线程池和单例模式&#xff0c;优雅地解决了后台任务…

OpenEuler操作系统中检测插入的USB设备并自动挂载

OpenEuler操作系统中检测插入的USB设备并自动挂载 项目需求&#xff1a;工控机上openeuler操作系统是无界面版本的&#xff0c;在工控机上连接了激光雷达&#xff0c;当激光雷达采集完数据&#xff0c;我们要将采集数据导入u盘&#xff0c;故需要在工控机上插入u盘&#xff0c;…

《Spring 中上下文传递的那些事儿》Part 11:上下文传递最佳实践总结与架构演进方向

&#x1f4dd; Part 11&#xff1a;上下文传递最佳实践总结与架构演进方向 经过前面几篇文章的深入探讨&#xff0c;我们已经系统性地学习了 Spring 应用中上下文传递的各种技术原理、常见问题以及解决方案。从 Web 请求上下文到异步任务、从多租户隔离到日志脱敏&#xff0c;…

使用云虚拟机搭建hadoop集群环境

使用云虚拟机搭建hadoop集群环境 安装jdk17 配置docker网络 docker network create --subnet172.18.0.0/16 hadoop 172.18.0.0&#xff1a;这是子网的网络地址&#xff0c;也就是这个网络的起始地址。/16&#xff1a;这是子网掩码&#xff08;Network Mask&#xff09;&#x…

【机器学习】吴恩达机器学习课程代码作业-Python版本

吴恩达老师的机器学习课程作业是MATLAB版本&#xff08;Octave&#xff09;的&#xff0c;现在有点过时了&#xff0c;我参考了几位大牛的代码&#xff0c;将作业改成了Python3.6版本&#xff0c;并做了中文注释&#xff0c;推荐使用Jupyter notebook。Python作业使用了原版数据…

2025年人工智能、虚拟现实与交互设计国际学术会议

重要信息 官网&#xff1a;www.aivrid.com 时间&#xff1a;2025年10月17-19日 地点&#xff1a;中国-东莞 部分介绍 征稿主题 包括但不限于&#xff1a; 生物特征 模式识别 机器视觉 专家系统 深度学习 智能搜索 自动编程 智能控制 智能机器…

SHA-256算法流程分析与详解——Github工程结合示例和动画演示

近日笔者在学习区块链的相关知识&#xff0c;接触到SHA-256算法&#xff0c;这里做一个知识梳理和总结。 强烈推荐大家自行去学习下面链接github上的工程&#xff0c;作者的动画演示和解释做的非常出色&#xff0c;逻辑非常清晰&#xff0c;B站搬运的对应的油管的讲解视频也放…

CSPNet: A New Backbone that can Enhance Learning Capability of CNN (CSP模块)

3. Method 方法 3.1 Cross Stage Partial Network 跨阶段局部网络 3.1.1 Cross Stage Partial Network 跨阶段局部网络 3.1.1.1 ResNet 和 DenseNet 的优缺点主流的卷积神经网络&#xff08;CNN&#xff09;架构&#xff0c;如ResNet [8]、ResNeXt [37]、DenseNet [11]&#x…

前端学习4:小白入门注册表单的制作(包括详细思考CSS、JS实现过程)

这篇我们来做一个简单表单&#xff0c;即常见的注册页面吧~学习完这篇我们将学习到Input、label、CSS伪类、CSS入门、更多的JS操作等。。一、首先明确需求&#xff1a;直接模仿常见的注册页面&#xff0c;包括&#xff1a;用户名、Email、性别&#xff08;单选按钮男/女&#x…

强化学习 (RL) 新突破:超越游戏,走向复杂现实决策

强化学习 (RL) 新突破&#xff1a;超越游戏&#xff0c;走向复杂现实决策 强化学习&#xff08;Reinforcement Learning&#xff0c; RL&#xff09;作为人工智能的核心范式之一&#xff0c;历经数十年的发展&#xff0c;正迎来一场深刻的范式转移。曾以战胜人类顶尖选手的Alph…

2025年6-7月AI领域关键进展:从药物研发到全球监管--AI深度融入产业与社会

2025年6月至7月&#xff0c;人工智能领域继续以惊人速度发展&#xff0c;在技术突破、行业应用、政策法规、企业战略及学术研究等方面取得了一系列重要里程碑。以下为关键动态&#xff1a;一、技术突破&#xff1a; AI向生命科学和认知科学纵深挺进DeepMind启动AI设计药物人体试…

【TOOL】ubuntu升级cmake版本

文章目录一、下载cmake脚本二、安装一、下载cmake脚本 在编译新工程时遇到cmake版本过低的情况&#xff0c;到 cmake官网 下载指定cmake安装脚本&#xff1a; 若需下载指定版本&#xff0c;见上图右上角蓝框。 二、安装 # 赋予可执行权限 sudo chmod x cmake-3.31.8-linux-x8…