系统--线程互斥

1、相关背景知识

临界资源 多线程、多执行流共享的资源,就叫做临界资源
临界区 每个线程内部,访问临界资源的代码
互斥 在任何时刻,保证有且只有一个执行流进入临界区,访问临界资源,对临界资源起到保护作用
原子性 不会被任何调度机制打断的操作,该操作只有两态,要么完成,要么没开始。(只要开始,必须完成了才能中断)

2、多线程工作的问题(抢票样例)

1、首先存在初始为100的票数tickets。

2、然后新建4个线程,进行抢票。

3、为了让tickets成为临界资源,将tickets初始为全局的。

int tickets = 100; // 票数
void Job(const std::string &name)
{
    while (true)
    {
        if (tickets > 0)
        {
            /*抢票*/
            usleep(1000);                                                                     // 1ms -> 抢票时间
            printf("who : %s , get a ticket , remain tickets : %d\n", name.c_str(), tickets); // 抢票
            tickets--;
        }
        else
        {
            break;
        }
    }
}

int main()
{
    Thread t1("thread-1", Job);
    Thread t2("thread-2", Job);
    Thread t3("thread-3", Job);
    Thread t4("thread-4", Job);

    t1.Start();
    t2.Start();
    t3.Start();
    t4.Start();

    t1.Join();
    t2.Join();
    t3.Join();
    t4.Join();

    return 0;
}

查看运行结果:

本来当remain tickets为0的时候,就不应该进入抢票逻辑了。

但是输出结果明显不对劲,票数都变为负数了,还在抢票。

为什么会出现这种情况呢?

多个线程并发的操作临界资源,就会带来一些问题。

因此,多个线程的临界区代码,必须具有互斥行为。

为了保证这个互斥行为,就引出了互斥量(即,加锁)。

3、锁

3.1、认识锁和接口

pthread_mutex_t pthread库提供的互斥锁类型
PTHREAD_MUTEX_INITIALIZER 如果锁是全局的或者静态的,可以直接mutex = PTHREAD_MUTEX_INITIALIZER进行初始化,并且最后不需要销毁
int pthread_mutex_init(pthread_mutex *restrict mutex, const pthread_mutexattr_t *restrict attr);

初始化锁。

restrict mutex:就是需要初始化的锁。

restrict attr:表示设置锁的属性,一般置空即可。

int pthread_mutex_destroy(pthread_mutex_t *mutex);

销毁锁。

用了init函数,才用destroy。

如果采用全局锁初始化的方式,不用destroy。

int pthread_mutex_lock(pthread_mutex_t *mutex); 加锁。当锁正在被占用的时候,调用lock函数的线程,阻塞等待锁被释放,然后继续竞争。
int pthread_mutex_trylock(pthread_mutex_t *mutex); 加锁。当锁正在被占用的时候,调用trylock函数的线程,争夺锁失败,直接返回一个指示值,告诉使用者是否争夺成功。
int pthread_mutex_unlock(pthread_mutex_t *mutex); 解锁。

3.2、加锁的时机/原则

1、加锁的力度(范围),一定要小。因为在临界区这,一个线程执行,其它线程全部阻塞。如果一直阻塞,导致效率降低。
2、任何时刻,访问临界区的线程,必须先要申请锁。否则会出现数据不一致问题。
3、加锁的前提,必须是线程都能看到这一把锁。因此,这把锁也是临界资源。但是不可能加锁之前又要加锁吧,这就套娃了。所以,加锁过程,是原子的。

4、如果线程申请锁失败,就阻塞原地,等着锁被释放,然后继续竞争。

反之,申请锁成功,就继续执行后续代码。

5、申请锁成功的线程,在访问临界区的时候,是可以被调度走的。

但是锁不会被释放,其它线程依然进不去。

即:对于其它线程来说,占据锁的线程,访问临界区,在它们看来是原子的。

3.3、对比不同加锁时机导致的不同现象(抢票样例)

3.3.1、while后加锁,if和else后都释放锁

void Job(const std::string &name)
{
    while (true)
    {
        pthread_mutex_lock(&g_mutex); // 加锁

        if (tickets > 0)
        {
            

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

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

相关文章

【短视频矩阵系统==saas技术开发】

在数字媒体领域,短视频的崛起已不可忽视。对于商业实体而言,掌握如何通过短视频平台有效吸引潜在客户并提高转化率,已成为一项关键课题。本文旨在深入剖析短视频矩阵系统的构成与作用机制,以期为企业提供一套系统化的策略&#xf…

Python语法基础(八)

🌈个人主页:羽晨同学 💫个人格言:“成为自己未来的主人~” 异常处理 这一个部分,我们来讲一下异常处理这部分。 异常特点 当程序执行的过程中,我们遇到了异常,而且异常未被处理,那么程序…

burp2

声明! 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下,如涉及侵权马上删除文章,笔记只是方便各位师傅的学习和探讨,文章所提到的网站以及内容,只做学习交流,其他均与本人以及泷羽sec团队无关&a…

linux 获取公网流量 tcpdump + python + C++

前言 需求为,统计linux上得上下行公网流量,常规得命令如iftop 、sar、ifstat、nload等只能获取流量得大小,不能区分公私网,所以需要通过抓取网络包并排除私网段才能拿到公网流量。下面提供了一些有效得解决思路,提供了…

React 路由与组件通信:如何实现路由参数、查询参数、state和上下文的使用

🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…

爬虫第四篇:Xpath 路径表达式全解析:从网页基础到爬取百度贴吧图片实战

简介:本文围绕 Xpath 路径表达式展开讲解,先是介绍了网页相关基础如 html、css、vue 以及前后端分离的概念与示例,包括各部分的结构、作用及简单代码展示,随后详细阐述了 xml 的节点关系、选取节点、谓语等理论知识,最…

七牛云成功保存但无法显示和访问{“error“:“download token not specified“}

在使用七牛云存储图片时,前端通过链接访问图片时遇到错误: {"error":"download token not specified"} 具体表现为: 后端通过 access_key 和 secret_key 生成了上传和下载的 Token。前端将域名与 res.key 拼接后生成图…

linux下环境变量的使用

文章目录 环境变量一、环境变量的定义与特点二、环境变量的分类三、常用的环境变量四 环境变量相关指令五 c语言获取环境变量接口六 通过代码如何获取环境变量 环境变量 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数 一、环境变量…

2-2-18-9 QNX系统架构之文件系统(三)

阅读前言 本文以QNX系统官方的文档英文原版资料为参考,翻译和逐句校对后,对QNX操作系统的相关概念进行了深度整理,旨在帮助想要了解QNX的读者及开发者可以快速阅读,而不必查看晦涩难懂的英文原文,这些文章将会作为一个…

基于 MVC 架构的 SpringBoot 高校行政事务管理系统:设计优化与实现验证

摘 要 身处网络时代,随着网络系统体系发展的不断成熟和完善,人们的生活也随之发生了很大的变化,人们在追求较高物质生活的同时,也在想着如何使自身的精神内涵得到提升,而读书就是人们获得精神享受非常重要的途径。为了…

vue3-Import declaration conflicts with local declaration of dayjs

同步发布于我的网站 🚀 概述错误描述 原代码报错信息 原因分析解决方案 修改导入语句使用泛型 代码解释总结 概述 在使用 Vue3 和 dayjs 时,可能会遇到一个常见的错误:“Import declaration conflicts with local declaration of ‘dayjs’…

【ubuntu-22.04】ubuntu-22.04搭建openwrt-23.05编译环境操作说明

ubuntu-22.04镜像下载 Index of /releases/22.04.1 安装ubuntu系统 安装openwrt-23.05依赖包 sudo apt update sudo apt install build-essential clang flex bison g++ gawk \ gcc-multilib g++-multilib gettext git libncurses-dev libssl-dev \ python3-distutils pyth…

html+css网页设计马林旅行社移动端4个页面

htmlcss网页设计马林旅行社移动端4个页面 网页作品代码简单,可使用任意HTML辑软件(如:Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改编辑等操作)。 获取源码 1&#…

【算法】位运算合集

阿华代码,不是逆风,就是我疯 你们的点赞收藏是我前进最大的动力!! 希望本文内容能够帮助到你!! 目录 零:位运算基础公式 零:五道基础题 1:位1的个数 2:比…

Android 硬件抽象层(HAL)全解析:智能设备硬件协同揭秘

在Android硬件抽象层(HAL)开发中,需要掌握许多底层技术,并熟悉如何将硬件驱动与Android系统的上层应用接口相集成。以下是HAL开发中需要掌握的核心技术和一些示例代码,以帮助理解其实现原理: 1. C/C编程和…

Linux如何将文件或目录打成rpm包?-- rpmbuild打包详解

👨‍🎓博主简介 🏅CSDN博客专家   🏅云计算领域优质创作者   🏅华为云开发者社区专家博主   🏅阿里云开发者社区专家博主 💊交流社区:运维交流社区 欢迎大家的加入&#xff01…

推荐学习笔记:矩阵补充和矩阵分解

参考: 召回 fun-rec/docs/ch02/ch2.1/ch2.1.1/mf.md at master datawhalechina/fun-rec GitHub 业务 隐语义模型与矩阵分解 协同过滤算法的特点: 协同过滤算法的特点就是完全没有利用到物品本身或者是用户自身的属性, 仅仅利用了用户与…

java引用第三方jar包,打包全流程

前言: 本文是使用maven引入第三方jar包,通过mvn命令打包。 以下为引入第三方jar包,打包进项目jar中的全流程步骤。 1、引入第三方jar包 1、放置路径 一般来说,放到项目(子项目)的resources的lib目录下。 2、pom引入 如图所示…

【webApp之h5端实战】首页评分组件的原生实现

关于评分组件,我们经常在现代前端框架中用到,UI美观效果丰富,使用体验是非常不错的。现在自己动手使用原生js封装下评分组件,可以用在自己的项目中。 组件实现原理 点击的❤左侧包括自己都是高亮的样式,右侧都是灰色的样式,这样就能把组件的状态区分开了。右边再加上辅…

基于Java Springboot旅游攻略APP且微信小程序

一、作品包含 源码数据库设计文档万字PPT全套环境和工具资源部署教程 二、项目技术 前端技术:Html、Css、Js、Vue、Element-ui 数据库:MySQL 后端技术:Java、Spring Boot、MyBatis 三、运行环境 开发工具:IDEA/eclipse 微信…