线程间的同步、如何解决线程冲突与死锁

news2024/11/16 13:45:25

一、线程同步概念:

线程同步是指在多线程编程中,为了保证多个线程之间的数据访问和操作的有序性以及正确性,需要采取一些机制来协调它们的执行。在多线程环境下,由于线程之间是并发执行的,可能会出现竞争条件(Race Condition)等问题,从而导致程序的不稳定性和错误。

案例与猜想:

示例1:

#include <iostream>
#include <windows.h>

int g;

DWORD WINAPI MyThreadProc (LPVOID lp){
    for(int i = 0; i < 100000000; i++){
        g++;
    }
    return 0;
}

int main(){
    HANDLE h = CreateThread(NULL, 0, MyThreadProc, NULL, 0, 0);
    
    for(int i = 0; i < 100000000; i++){
        g++;
    }

    std::cout << g << std::endl;
    
    CloseHandle(h);
    return 0;
}

结果:

 

这里测试了两个次,当多个线程同时对公共资源进行操作时,会发生错误,该示例结果始终处在 

 100000000~200000000之间

猜测一:主线程可能先走完,然后输出g,并退出。

示例2:

因此在这里继续添加一个等待线程函数(WaitForSingleObject)等待线程结束试试

 

发现依旧无法达到预期。

 猜测二:线程与线程之间存在同步,使得g在某一个或某一些值时,g在主线程与线程中,只增加一次。

二、解决方法

常见的线程同步机制包括:

        1. 互斥锁(Mutex):互斥锁是一种保护共享资源的机制,它确保在任意时刻只有一个线程能够访问被保护的资源。当一个线程获得了互斥锁,其他线程就需要等待锁的释放才能访问资源。

        2. 信号量(Semaphore):信号量是一种用于控制同时访问某一资源的线程数目的方法。它可以允许多个线程同时访问资源,但是可以通过信号量的计数来控制同时访问的线程数量。

        3. 条件变量(Condition Variable):条件变量用于在某些特定条件下使线程等待或唤醒。它通常与互斥锁一起使用,以实现在满足特定条件时线程的阻塞和唤醒。

        4. 读写锁(Read-Write Lock):读写锁允许多个线程同时读取共享资源,但是在写操作时需要互斥锁来保护资源,以避免多个线程同时写入导致数据不一致性。

        5. 原子操作(Atomic Operations):原子操作是一种不可分割的操作,能够保证在多线程环境下的执行不会被中断,从而避免竞争条件。

线程同步的目的是确保线程之间的协调和有序执行,以避免数据竞争和其他并发问题。选择合适的线程同步机制取决于具体的应用场景和需求。

1.互斥锁(Mutex):

PS:临界区同样存在计数机制,进入几次临界区,就要退出几次临界区

示例:

#include <iostream>
#include <windows.h>

int g;

CRITICAL_SECTION g_cs;//创建互斥锁

DWORD WINAPI MyThreadProc (LPVOID lp){
    for(int i = 0; i < 100000000; i++){
        EnterCriticalSection(&g_cs);    //进入临界区
        g++;
        LeaveCriticalSection(&g_cs);    //离开临界区
    }
    return 0;
}

int main(){
    InitializeCriticalSection(&g_cs);//初始化互斥锁

    HANDLE h = CreateThread(NULL, 0, MyThreadProc, NULL, 0, 0);
    

    for(int i = 0; i < 100000000; i++){
        EnterCriticalSection(&g_cs);    //进入临界区
        g++;
        LeaveCriticalSection(&g_cs);    //进入临界区
    }

    WaitForSingleObject(h, INFINITE);

    std::cout << g << std::endl;
    
    CloseHandle(h);
    DeleteCriticalSection(&g_cs);
    return 0;
}

结果:

 

需要注意的是,过多地使用互斥锁可能会导致性能问题,因为只有一个线程能够执行临界区代码,其他线程需要等待

 未完待续……

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

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

相关文章

VUE框架:vue2转vue3全面细节总结(2)导航守卫

大家好&#xff0c;我是csdn的博主&#xff1a;lqj_本人 这是我的个人博客主页&#xff1a; lqj_本人_python人工智能视觉&#xff08;opencv&#xff09;从入门到实战,前端,微信小程序-CSDN博客 最新的uniapp毕业设计专栏也放在下方了&#xff1a; https://blog.csdn.net/lbcy…

学习源码,模仿编程

一.观察者模式: 1.创建事件 2.发布事件 3.监听事件 4.效果: 二.模板方法模式

【云原生】使用kubeadm搭建K8S

目录 一、Kubeadm搭建K8S1.1环境准备1.2所有节点安装docker1.3所有节点安装kubeadm&#xff0c;kubelet和kubectl1.4部署K8S集群1.5所有节点部署网络插件flannel 二、部署 Dashboard 一、Kubeadm搭建K8S 1.1环境准备 服务器IP配置master&#xff08;2C/4G&#xff0c;cpu核心…

如何下载和编译 Android 源码?

本文为洛奇看世界(guyongqiangx)原创&#xff0c;转载请注明出处。 文章链接&#xff1a;https://blog.csdn.net/guyongqiangx/article/details/132125431 网上关于如何下载 Android 源码和编译的文章很多&#xff0c;其中最常见的就是 Android 官方文档&#xff1a; 下载源代码…

前端js--扩展卡片

效果图 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><link rel"stylesheet" href"…

谈一谈Python中的装饰器

1、装饰器基础介绍 1.1 何为Python中的装饰器&#xff1f; Python中装饰器的定义以及用途&#xff1a; 装饰器是一种特殊的函数&#xff0c;它可以接受一个函数作为参数&#xff0c;并返回一个新的函数。装饰器可以用来修改或增强函数的行为&#xff0c;而不需要修改函数本身…

使用JProfiler进入JVM分析

要评测JVM&#xff0c;必须将JProfiler的评测代理加载到JVM中。这可以通过两种不同的方式发生&#xff1a;在启动脚本中指定-agentpath VM参数&#xff0c;或者使用attach API将代理加载到已经运行的JVM中。 JProfiler支持这两种模式。添加VM参数是评测的首选方式&#xff0c;集…

拥抱创新:用Kotlin开发高效Android应用

拥抱创新&#xff1a;用Kotlin开发高效Android应用 引言 在当今数字时代&#xff0c;移动应用已经成为人们生活中不可或缺的一部分。无论是社交媒体、电子商务还是健康管理&#xff0c;移动应用已经深刻地影响了我们的生活方式。随着移动设备的普及和功能的增强&#xff0c;A…

【JAVA】类和对象

作者主页&#xff1a;paper jie的博客 本文作者&#xff1a;大家好&#xff0c;我是paper jie&#xff0c;感谢你阅读本文&#xff0c;欢迎一建三连哦。 本文录入于《JAVASE语法系列》专栏&#xff0c;本专栏是针对于大学生&#xff0c;编程小白精心打造的。笔者用重金(时间和精…

高项V4.高级PM.项目集set+项目组合portfolio+组织级OPM+量化项目管理+实践模型

PMI &#xff0c; ITSS 、CMMI 和PRINCE2 等为各类信息系统项目管理提供了最佳实践&#xff0c;井提供了对组织的项目管理能力进行持续改进和评估的方法。 第一部分 项目集--《项目集管理标准>> (第4 版) ---实现项目11>2的更大效益 由项目管理协会(PMI) 出版的《…

OpenCV之信用卡识别实战

文章目录 代码视频讲解模板匹配文件主程序(ocr_template_match.py)myutils.py 代码 链接: https://pan.baidu.com/s/1KjdiqkyYGfHk97wwgF-j3g?pwdhhkf 提取码: hhkf 视频讲解 模板匹配文件 主程序(ocr_template_match.py) # 导入工具包 from imutils import contours # 从…

算术逻辑单元(ALU)(数电、加法器)

优先级&#xff1a;与>或 异或电路 依旧需要一级级的传递&#xff0c;后算完才能前传

[oeasy]python0079_控制序列_光标位置设置_ESC_逃逸字符_CSI

光标位置 回忆上次内容 上次我们研究的比较杂 类型转化进制转化捕获异常版本控制生成帮助文档变量的常用类型变量的生命周期控制 数据类型主要研究了两个 字符串 str 整型数字 int 字符串型 和 整型数字型变量 是可以相互转化的 加法运算逻辑 会根据操作变量的不同 而不同…

针对java程序员的了解细节操作系统与进程

一、&#x1f49b; 操作系统&#xff08;浅浅概念&#xff09;&#xff1a;是用来搞管理软件的 1.对下,要管理各种硬件设备 2.对上,要给应用程序提供一个稳定的运行环境 二、&#x1f499; 进程&#xff1a;正在运行的程序&#xff0c;假如程序没有运行就不叫程序&#xff0c;…

如何在终端设置代理(设置jupyter notebook同理)

设置代理 在终端(我用的gitbash)下执行 set HTTP_PROXYhttp://<user>:<password><proxy server>:<proxy port> set HTTPS_PROXYhttp://<user>:<password><proxy server>:<proxy port>其中&#xff1a; user、password&#…

LabVIEW开发3D颈动脉图像边缘检测

LabVIEW开发3D颈动脉图像边缘检测 近年来&#xff0c;超声图像在医学领域对疾病诊断具有重要意义。边缘检测是图像处理技术的重要组成部分。边缘包含图像信息。边缘检测的主要目的是根据强度和纹理等属性识别图像中均匀区域的边界。超声&#xff08;US&#xff09;图像存在视觉…

SpringMVC视图

SpringMVC视图 视图的作用是渲染数据&#xff0c;将模型Model中的数据展示给客户&#xff0c;SpringMVC中视图的种类有很多&#xff0c;默认有转发视图(InternalResourceView)和重定向视图(RedirectView)。 当工程引入jstl的依赖&#xff0c;转发视图会自动跳转jstlView,若使用…

11.物联网操作系统内存管理

一。STM32编译过程及程序组成 STM32编译过程 程序的组成、存储与运行 MDK生成的主要文件分析 1.STM32编译过程 1.源文件&#xff08;Source code&#xff09;--》目标文件&#xff08;Object code&#xff09; .c(C语言)通过armcc生成.o&#xff0c;.s&#xff08;汇编&…

附件展示 点击下载

效果图 实现代码 <el-table-column prop"attachment" label"合同附件" width"250" show-overflow-tooltip><template slot-scope"scope"><div v-if"scope.row.cceedcAppendixInfoList &&scope.row.ccee…

背包问题详解(动态规划):01背包、完全背包、多重背包

动态规划&#xff1a; 基本思想&#xff1a; 动态规划算法通常用于求解具有某种最优性质的问题。在这类问题中&#xff0c; 可能会有很多可行解。没一个解都对应于一个值&#xff0c;我们希望找到具有最优值的解。胎动规划算法与分治法类似&#xff0c;其基本思想也是将待求解…