Linux入门之多线程|线程的互斥|锁|封装线程|封装锁|死锁

news2024/11/26 21:41:43

文章目录

一、线程互斥

1.概念

二、线程互斥接口

1.互斥量的接口

初始化互斥量

互斥量的的加锁和解锁

销毁互斥量

2.互斥量的原理

三、线程的封装

四、锁的封装

五、死锁

1.死锁的概念

2.产生死锁的必要条件:

3.避免死锁:核心思想 破环死锁的4个必要条件的任意一个

总结



多线程中有一个全局变量,是被所有执行流共享的。线程中,大部分资源都会直接或间接共享。只要存在共享,就可能存在并发访问的问题,进而导致数据不一致问题。

一、线程互斥

1.概念

  • 临界资源:多线程执行流共享的资源就叫做临界资源(对共享资源进行一定的保护)
  • 临界区:任何一个线程,都有代码,访问临界资源。线程中的访问临界资源的代码称为临界区。
  • 非临界区:线程中不访问临界资源的代码称为非临界区。
  • 互斥:任何时刻,互斥保证有且只有一个执行流进入临界区,访问临界资源,通常对临界资源起保护作用。
  • 原子性:不会被任何调度机制打断的操作,该操作只有两种状态,要么完成,要么未完成

二、线程互斥接口

1.互斥量的接口

初始化互斥量

  1. 静态分配 (静态分配的锁不需要被销毁)
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

     2.动态分配

int pthread_mutex_init(phthread_mutex_t * restrict mutex, const pthread_mutexattr_t * restict attr);

参数:mutex 要初始化的互斥量
     attr:null

互斥量的的加锁和解锁

int pthread_mutex_lock(pthread_mutex_t * mutex);
int pthread_mutex_unlock(pthread_mutex_t * mutex);
//成功返回0,失败返回错误码

  • 调用pthread_lock时候,可能有两种情况:互斥量处于未锁状态,该函数将互斥量锁定,同时返回成功

  • 发起函数调用时,其他线程已经锁定互斥量,或者存在其他线程同时申请互斥量,但是没有竞争到互斥量,那么pthread_lock将会阻塞(执行流被挂起),等待互斥量解锁。

销毁互斥量

不要销毁一个已经加锁的互斥量

已经销毁的互斥量,要确保后面不会有线程再尝试加锁

int pthread_mutex_destroy(pthread_mutex_t * mutex);

2.互斥量的原理

          为了实现互斥锁的操作,大多数体系结构提供了swap或者exchange指令,该指令的作用是把寄存器和内存单元的数据进行交换。由于只有一条指令,保证了原子性,即使是多处理器平台,访问内存的总线周期也有先后,一个处理器上的交换指令执行时,另一个处理器的交换指令只能等待总线周期。

        共享资源是要存储到内存中,mutex再内存中,起始mutex = 1,有两个线程A和B,调度器先执行线程A的工作,A将寄存器中的值先初始化为0,然后A将内存和cpu中的数据进行交换,此时寄存器中的值为1,内存中的值为0,A获得了这把锁。时间片到了,B开始执行,B将寄存器中的值改为0,自己去执行交换的时候内存里mutex = 0,此时线程被挂起。

三、线程的封装

class Thread
{
   public:
    typedef enum
    {
        NEW = 0,
        RUNNING,
        EXITED
    }ThreadStatus;

    typedef void(*func_t)(void *);
    
    //构造
    Thread(int num,func_t fun,void * args)
    :_tid(0),_status(NEW),_func(func),_args(args)
    {
        char name[128];
        snprintf(name,sizeof(name),"thread - % d",num);
        _name = name;
    }

    int status() { return _status;}
    std::string threadname() {return _name;}
    pthread_t thread_id()
    {
        if(_status == RUNNING) return _tid;
        else return 0;
    }

    static void * runHelper(void * args)
    {
        Thread * ts = (Thread * )args; // 拿到了当前对象
        (*ts)();
        return nullptr;
    }


    void operator()()
    {
        if(_func!= nullptr) _func(_args);
    }

    //创建线程
    void run()
    {
        int n = pthread_create(&_tid,nullptr,runHelper,this);
        if( n!= 0) exit(1);
        _status = RUNNING;
    }

    void join()
    {
        if n = pthread_join(_tid,nullptr);
        if(n!= 0) return ;
        status = EXITED;
    }

    ~Thread()
    {}



    private:
        pthread_t _tid;
        std::string _name;
        func_t _func; //线程未来要执行的回调
        void * args;
};

四、锁的封装

#pragma once 

#include<iostream>
#include<pthread.h>

int tickets = 1000; //抢票 共享资源

pthread_mutex_mutex =   PTHREAD_MUTEX_INITIALIZER;


class Mutex   //自己不维护锁,由外部传入
{
public:
    Mutex(pthread_mutex_t * mutex)
    :_pmutex(mutex)
    {}
    
    void lock()
    {
        pthread_mutex_lock(_pmutex);
    }

    void unlock()
    {
        pthread_mutex_unlock(_pmutex);
    }

    ~Mutex()
    {}

   private:
    pthread_mutex_t * _pmutex;
  
};


class LockGuard
{   public:
        LockGuard(pthread_mutex_t * mutex)
        :_mutex(mutex)
    {
        _mutex.lock();
    }

    ~LockGuard()
    {
        _mutex.unlock();
    }


    private:
        Mutex _mutex;
}; 


void threadRoutine(void * args)
{
    std::string message = static_cast<const char *>(args);
    while(true)
    {
        LockGuard lockguard(&mutex);
        if(ticktes > 0)
        {
            usleep(200);
            cout<<message<<"get a ticket: "<<tickets --<<endl; //临界区
        }

        else
        {
            break;
        }
    }

    //抢完票后续的动作放入用户数据库中
    usleep(1000);
    LockGuard lockguard(&mutex);
}

int main()
{
    Thread t1(1, threadRoutine, (void *)"1");
    Thread t2(2, threadRoutine, (void *)"2");
    Thread t3(3, threadRoutine, (void *)"3");
    Thread t4(4, threadRoutine, (void *)"4");

   
    return 0;
}

五、死锁

多线程代码存在并发访问临界资源的问题,所以产生了加锁的策略。加锁之后可能导致死锁。

1.死锁的概念

2.产生死锁的必要条件:

1.互斥条件:一个资源每次只能被一个执行流使用

2.请求与保持:一个执行流因请求资源而阻塞,对已获得的资源保持不妨

3.环路等待(循环等待条件):若干执行流之间形成一种头尾相接的循环等待资源的关系

4.不剥夺条件:一个执行流已获得的资源,在未使用完之前,不能强行剥夺

3.避免死锁:核心思想 破环死锁的4个必要条件的任意一个

解决死锁问题:1.不加锁 2.主动释放锁 3.按照顺序申请锁 4.控制线程统一释放锁


总结

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

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

相关文章

算法训练day36|贪心算法 part05(重叠区间三连击:LeetCode435. 无重叠区间763.划分字母区间56. 合并区间)

文章目录 435. 无重叠区间思路分析 763.划分字母区间思路分析代码实现思考总结 56. 合并区间思路分析 435. 无重叠区间 题目链接&#x1f525;&#x1f525; 给定一个区间的集合&#xff0c;找到需要移除区间的最小数量&#xff0c;使剩余区间互不重叠。 注意: 可以认为区间的…

Python,如何安装lap,pip安装lap出现问题

Linux可以&#xff1a; pip install cpython pip install gitgit://github.com/gatagat/lap.gitwindows可以&#xff1a; 下载https://github.com/gatagat/lap 后解压&#xff0c; 安装pip install cpython 安装VS2019企业版&#xff1a; key BF8Y8-GN2QH-T84XB-QVY3B-RC4D…

老师如何使用易查分创建一个成绩查询系统

在现代教育管理中&#xff0c;成绩查询是一个非常重要的环节。传统的成绩查询方式通常是将成绩表格发放给学生家长&#xff0c;这样不仅浪费了大量的纸张&#xff0c;而且还存在信息泄露的风险。为了解决这个问题&#xff0c;让成绩查询更加方便快捷&#xff0c;推荐老师可以使…

移动APP性能测试有什么注意事项?

移动APP性能测试是移动应用开发过程中非常重要的一个环节&#xff0c;它能够有效地评估和验证应用在不同环境下的性能表现&#xff0c;为开发者提供宝贵的参考和改进的方向。在进行移动APP性能测试时&#xff0c;有一些注意事项需要我们关注&#xff0c;并且在测试完成后&#…

OLED透明屏 双拼:开启显示技术的未来

OLED透明屏 双拼作为一项突破性的显示技术&#xff0c;正以其独特的双拼设计和创新的应用领域引起广泛关注。 据市场研究报告显示&#xff0c;OLED透明屏 双拼市场规模预计将在未来几年内达到数十亿美元。 本文将通过介绍OLED透明屏 双拼的优势和特点、应用领域、技术原理以及…

【探索Linux】—— 强大的命令行工具 P.7(进程 · 进程的概念)

阅读导航 前言一、冯诺依曼体系结构二、操作系统&#xff08;OS&#xff09;1. 概念 三、进程1. 进程的概念2. PCB&#xff08;Process Control Block&#xff09;3. 查看进程 四、fork函数1. 函数简介2. 调用方式3. 返回值4. 使用示例 五、进程的几种状态1. 状态简介2. 进程状…

基于边缘物联网关的智慧零售应用方案

推动经济健康发展增长&#xff0c;就要持续促进和扩大消费需求&#xff0c;提升消费体验。随着物联网技术的普及&#xff0c;面向日常消费的智慧零售应用迎来爆发式增长&#xff0c;不仅可以提升消费者消费体验&#xff0c;还可以提高商家营销和管理效率。本篇就为大家简单介绍…

Flink+Flink CDC版本升级的依赖问题总结

之前使用Flink1.13Flink CDC2.0同步MySQL数据&#xff0c;想测试一下最新的几个版本。但是各种依赖冲突的报错&#xff0c;经过一段时间的调试&#xff0c;终于解决&#xff0c;现在总结一下。 1、flink1.15前后jar包名称不一样 flink-streaming-java、flink-clients、flink-…

VR电气低压试验仿真教学系统软件激发学生的学习兴趣

智慧化时代&#xff0c;电力设备试验仿真培训也逐渐与先进科技相结合&#xff0c;借助VRAR技术创造一个高逼真、安全、沉浸感的实验和设计平台。 在虚拟环境中&#xff0c;元宇宙VR会模拟各种触电场景&#xff0c;比如大风刮断架空线、接户线搭落在金属物、相线和电杆拉线褡裢、…

机器学习_特征工程_特征数据的评价标准

本文主要从 单特征分析&#xff0c;多特征筛选&#xff0c;特征监控&#xff0c;外部特征评估的几个方面对特征数据进行阐述。 来源 &#xff1a; 特征筛选_特征覆盖度怎么算_adamyoungjack的博客-CSDN博客 1. 单特征分析 1.1 简介 好特征可以从几个角度衡量&#xff1a;覆…

Nacos docker实现nacos高可用集群项目

目录 Nacos是什么&#xff1f; Nacos在公司里的运用是什么&#xff1f; 使用docker构建nacos容器高可用集群 实验规划图&#xff1a;​编辑 1、拉取nacos镜像 2、创建docker网桥&#xff08;实现集群内的机器的互联互通&#xff08;所有的nacos和mysql&#xff09;&#x…

javaScript:DOM中常用尺寸

目录 前言&#xff08;可以根据图示找到需要的尺寸&#xff0c;便于理解&#xff09; 内尺寸 clientWidth 包含左右padding和宽度width&#xff08;忽略滚动条的宽度&#xff09; clientHeight 包含上下padding和height&#xff08;忽略滚动条的高度&#xff09; clientTo…

postman json复杂数据的模拟

先设置路径 然后可以定义下边数据&#xff08;Key value&#xff09; 也可以不定义 看你的情况 [{"mac": "4C-77-66-19-50-65","addressPattern": "98jd","platform": "ios","registrationId": "…

国内免费无限制的chatgpt导航和ai画画

非常实用的AI网址导航&#xff0c;其实际使用体验非常便捷。该导航系统不仅提供了全面的网站分类和搜索功能&#xff0c;还对每个网站进行了精准的评估和排序。推荐高质量的网站资源&#xff0c;并实时检测网站的安全性&#xff0c;保障用户的上网安全。 总的来说&#xff1a…

KaiwuDB 受邀亮相 2023 中国国际“软博会”

8月31日&#xff0c;第二十五届中国国际软件博览会&#xff08;以下简称“软博会”&#xff09;在天津盛大开幕。KaiwuDB 受邀亮相展会&#xff0c;围绕“塑造软件新生态&#xff0c;赋能发展新变革”主题&#xff0c;重点展示自研分布式多模数据库及各大行业解决方案&#xff…

Docker Part01:Docker简介

文章目录 1 虚拟化技术2 Docker概述2.1 Docker能解决的问题2.2 Docker介绍2.3 为什么使用Docker2.4 Docker特点2.5 Docker应用场景 3 Docker与虚拟机对比3.1 Docker和虚拟机组成结构3.2 Docker和虚拟机的不同点 4 Docker基本概念4.1 Docker引擎4.2 Docker基本架构4.3 Docker容器…

地图投影——1 投影目录

地图投影示例说明亚当斯方形 II该投影以方形显示世界。该投影为等角投影&#xff0c;但方形的四个角除外。埃托夫该折衷改进的方位投影采用椭圆的形式。该投影主要用于世界地图。阿尔伯斯该等积圆锥投影最适合用于中纬度东西方向分布的大陆板块。方位自适应圆柱该折衷的地图投影…

ToBeWritten之ATTCK 测评方案

也许每个人出生的时候都以为这世界都是为他一个人而存在的&#xff0c;当他发现自己错的时候&#xff0c;他便开始长大 少走了弯路&#xff0c;也就错过了风景&#xff0c;无论如何&#xff0c;感谢经历 转移发布平台通知&#xff1a;将不再在CSDN博客发布新文章&#xff0c;敬…

FLUX查询InfluxDB -- InfluxDB笔记三

1. 入门 from(bucket: "example_query") // 没有筛选条件直接查询会报错|> range(start: -1h) // |>是管道符&#xff0c;后跟筛选条件 2. 序列、表和表流 序列是InfluxDB的概念&#xff0c;一个序列是由measurement、标签集、一个字段名称 表流是FLUX为了…

基于FPGA的信号发生器(三角波、方波、正弦波)

目录 DDS实现原理 DDS整体设计框图​ Quartus II 仿真​ modelsim仿真 顶层代码 DDS实现原理 DDS(Direct Digital Frequency Synthesizer)直接数字频率合成器,也可叫DDFS。 DDS是从相位的概念直接合成所需波形的一种频率合成技术。 不仅可以产生不同频率的正弦波,而且可…