线程同步及互斥锁

2023-11-06

线程同步的概念

线程同步,指一个线程发出某一功能调用时,在没有得到结果之前,该调用不返回。同时其它线程为保证数据一致性,不能调用该功能。

 线程同步的例子

创建两个线程,让两个线程共享一个全局变量int number, 然后让每个线程数5000次数,看最后打印出这个number值是多少?

线程A代码段:

线程B代码段:

 

 

代码片段说明:

代码中使用调用usleep是为了让两个子线程能够轮流使用CPU,避免一个子线程在一个时间片内完成5000次数数。对number执行++操作,使用了中间变量cur是为了尽可能的模拟cpu时间片用完而让出cpu的情况。

 

测试结果:经过多次测试最后的结果显示,有可能会出现number值少于5000*2=10000的情况。

分析原因:

        假如子线程A执行完了cur++操作,还没有将cur的值赋值给number失去了cpu的执行权,子线程B得到了cpu执行权,而子线程B最后执行完了number=cur,而后失去了cpu的执行权;此时子线程A又重新得到cpu的执行权,并执行number=cur操作,这样会把线程B刚刚写回number的值被覆盖了,造成number值不符合预期的值。

如何解决这个问题:

         Linux中提供一把互斥锁mutex(也称之为互斥量)。每个线程在对资源操作前都尝试先加锁,成功加锁才能操作,操作结束解锁。

        资源还是共享的,线程间也还是竞争的,但通过“锁”就将资源的访问变成互斥操作,而后与时间有关的错误也不会再产生了。

 

        线程1访问共享资源的时候要先判断锁是否锁着,如果锁着就阻塞等待;若锁是解开的就将这把锁加锁,此时可以访问共享资源,访问完成后释放锁,这样其他线程就有机会获得锁。

        应该注意的是:图中同一时刻,只能有一个线程持有该锁,只要该线程未完成操作就不释放锁。使用互斥锁之后,两个线程由并行操作变成了串行操作,效率降低了,但是数据不一致的问题得到解决了。

互斥锁主要相关函数

pthread_mutex_t mutex;定义互斥锁

pthread_mutex_init(&mutex, NULL);互斥锁初始化 

pthread_mutex_lock(&mutex);加锁

pthread_mutex_unlock(&mutex);解锁

pthread_mutex_destroy(&mutex);销毁互斥锁
 

#include <stdio.h>
#include<iostream>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>
using namespace std;

#define NUM 20000
int number = 0;

//定义一把锁
pthread_mutex_t mutex;

void *mythread1(void *args)
{
        int i = 0;
        int n;
        for (i = 0; i < NUM; i++)
        {
                //加锁
                pthread_mutex_lock(&mutex);
                n = number;
                n++;
                number = n;
                cout << "[" << n << "]" << endl;
                //解锁
                pthread_mutex_unlock(&mutex);
        }



}


void *mythread2(void *args)
{
        int i = 0;
        int n;
        for (i = 0; i < NUM; i++)
        {
                //加锁
                pthread_mutex_lock(&mutex);
                n = number;
                n++;
                number = n;
                cout << "[" << n << "]" << endl;
                //解锁
                pthread_mutex_unlock(&mutex);
        }

}

int main()
{
        int ret;
        pthread_t thread1;
        pthread_t thread2;


        //互斥锁初始化
        pthread_mutex_init(&mutex, NULL);

        ret = pthread_create(&thread1, NULL, mythread1, NULL);
        if(ret!=0)
        {
                cout << "pthread_create error, " << strerror(ret) << endl;
                return -1;
        }

        ret = pthread_create(&thread2, NULL, mythread2, NULL);
        if(ret!=0)
        {
                cout << "pthread_create error, " << strerror(ret) << endl;
                return -1;
        }

        //等待线程结束
        pthread_join(thread1, NULL);
        pthread_join(thread2, NULL);

        //释放互斥锁
        pthread_mutex_destroy(&mutex);
        return 0;
}

 多跑几次代码之后结果还是40000,成功的使用互斥锁消除了线程同步问题。

 

 

 

 

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

线程同步及互斥锁 的相关文章

  • /usr/bin/as:无法识别的选项“-EL”

    因此 在为我的1plus手机编译android内核时 经过3天的多次尝试 我放弃了并尝试在这里询问是否有人以前遇到过这个问题 这个错误对我来说有点模糊 但我觉得问题来自于我最近对 GNU Linux 发行版 Gentoo 的更改 它在不应该
  • 尝试编译 git 但在 linux 中找不到 libcurl

    我想编译支持 http https 的 git 我有 ls usr include curl curlbuild h curl h curlrules h curlver h easy h mprintf h multi h stdchea
  • 对于客户端服务器程序,并行接收多个客户端连接请求的最佳方法是什么?

    该程序是在 Linux 上用 C 语言开发的客户端服务器套接字应用程序 每个客户端都连接到一个远程服务器并将其自身记录为在线 在任何给定时间点很可能有多个客户端在线 所有客户端都尝试连接到服务器以将自己记录为在线 忙碌 空闲等 那么服务器如
  • 如何从 Linux 命令行打开 Sublime Text 2 文件到选项卡,而不是新窗口

    我有 ST2 设置 这样我就可以执行 sublime file txt 它将在 ST2 窗口中打开 但是我怎样才能让它在当前打开的窗口的新选项卡中打开呢 尝试 Sublime 命令行帮助 subl 帮助 Sublime Text 2 内部版
  • 如何使用 shell 脚本解压所有 .tar.gz?

    我试过这个 DIR path tar gz if ls A DIR 2 gt dev null then echo not gz else tar zxvf path tar gz C path tar fi 如果该文件夹有一个 tar 则
  • 使用 xargs 时如何获取退出代码(并行)

    我制作了一个用于启动并行 rsync 进程的脚本 bin bash LIST 1 DEST DIR 2 RSYNC OPTS 3 echo rsyncing From SRC DIR To DEST DIR RSYNC OPTS RSYNC
  • 打破条件变量死锁

    我遇到这样的情况 线程 1 正在等待条件变量 A 该变量应该由线程 2 唤醒 现在线程 2 正在等待条件变量 B 该变量应该由线程 1 唤醒 在我使用的场景中条件变量 我无法避免这样的死锁情况 我检测到循环 死锁 并终止死锁参与者的线程之一
  • Bash 脚本错误 [重复]

    这个问题在这里已经有答案了 我想知道下面的脚本有什么错误 我收到错误为 command not foundh line 1 command not foundh line 2 其连续的 我试过添加 但现在工作请告诉我该怎么做 bin bas
  • Tomcat 中的 403 访问被拒绝

    我有以下内容tomcat users xml
  • pip 找不到满足要求的版本 django==2.2.1

    我刚刚将操作系统更改为 linux 并且想安装 django 但我无法安装最新版本的 django 我努力了 pip install django 但是它安装了 django 1 11 11 这不是我需要的 我还将我的 pip 升级到了 1
  • Docker容器内的动态监听端口

    我有一个应用程序 在使用其默认端口建立一些连接后 开始打开 侦听 新的随机端口来处理现有连接 然后删除它们 视频通话 它还在通信协议内交换其IP地址和端口 我能够解决IP地址问题 但仍然无法找到一种方法来动态告诉主机的IPTABLES在Do
  • 如何在 .zip 文件中使用 grep

    有 3 个文件 a csv b csv c csv 压缩为 abh zip 现在可以在 abh zip 上执行 grep 命令 是否有任何通配符 仅对里面的 c csv 文件运行 grep压缩 如果你有zipgrep 据我所知 它是随zip
  • 分割 tar.bz2 文件并单独提取每个文件

    我可以将一个大的 tar bz2 文件分割成几个较小的文件并在 Ubuntu 中单独提取这些小 tar bz2 文件吗 Thanks 我认为这不容易实现 A tar bz2是单个流 它没有像这样的索引zip这将允许跳到存档中特定文件的开头
  • 使用多个 NIC 广播 UDP 数据包

    我正在 Linux 中为相机控制器构建嵌入式系统 非实时 我在让网络做我想做的事情时遇到问题 该系统有 3 个 NIC 1 个 100base T 和 2 个千兆端口 我将较慢的连接到相机 这就是它支持的全部 而较快的连接是与其他机器的点对
  • 在 Windows 下对 Unix 下创建的文件使用 fstream::seekg

    我有一个C 跨平台程序 在Linux下用g 编译 在PC下用Visual Studio编译 该程序将行写入文本文件 使用 lt lt 运算符和std endl 但也可以从生成的文本文件中读回数据 使用std getline 为了优化数据访问
  • 如何在 arago 项目构建中编写自己的食谱包

    我如何在 arago 项目构建中编写自己的食谱包 我知道它可以是 bitbake 文件 但我怎么写 不知道 我在互联网上搜索 但未能找到任何好的来源 有人可以给我提供链接或示例来开始吗 RegardsLinux 学习者 使用 Bitbake
  • 是否有一种异步信号安全的方式来读取 Linux 上的目录列表?

    SUSv4 http pubs opengroup org onlinepubs 9699919799 functions V2 chap02 html tag 15 04 03 03未在其异步信号安全函数列表中列出 opendir rea
  • Linux 从设备本身运行的脚本卸载设备

    我在路径中安装了一个 iso 映像 mnt iso 在这个 iso 中我有一个安装脚本 install sh 我从 iso 运行安装脚本 最后脚本询问用户是否要卸载 iso 本身 如果用户按 y 脚本将执行以下代码 cd umount mn
  • Linux 内核中是否使用了扩展指令集(SSE、MMX)?

    好吧 它们带来 至少应该带来 性能的巨大提升 不是吗 所以 我还没有看到任何 Linux 内核源代码 但很想问 它们是否以某种方式被使用 在这种情况下 对于没有此类指令的系统 必须有一些特殊的 代码上限 SSE 和 MMX 指令集在音频 视
  • 设置 nginx 具有多个 IP

    我的 nginx 配置文件位于 etc nginx sites available 下 有两个上游说 upstream test1 server 1 1 1 1 50 server 1 1 1 2 50 upstream test2 ser

随机推荐

  • 下载vimeo视频_使用Vimeo的API和Slim构建基本的视频搜索应用

    下载vimeo视频 In this tutorial you ll get to know the basics of the Vimeo API With it you can fetch information on a specifi
  • git本地分支修改名称

    给一个git分支改名的方法很简单 如果对于分支不是当前分支 可以使用下面代码 git branch m 原分支名 新分支名 如果是当前 那么可以使用加上新名字 git branch m 新分支名称
  • 密码编码学与网络安全(2):对称密码之传统加密技术

    对称密码之传统加密技术 关于对称加密 对称密码模型 密码编码学 密码分析学与穷举攻击 古典加密算法 代替技术 置换技术 转轮机 隐写术 关于对称加密 对称加密 也称为传统加密或单密钥加密 是20世纪70年代公钥密码产生之前唯一的 加密类型
  • 达梦数据库图形化界面工具打开常见报错

    在使用工具时 有时会存在打开报错的情况 最常见的就是manager及dts 某次练习时dts产生了如下报错 此类报错基本都是由于用root用户启动了某些需要用dmdba用户启动的程序 导致部分目录及包的权限受到影响变为root root 比
  • Maven基础——什么是Maven

    目录 Maven概述 一 什么是maven 二 Maven能解决什么问题 三 依赖管理的概念 四 一键构建概念 Maven基础 Maven安装与仓库类型介绍 Maven概述 一 什么是maven Maven是一个项目管理工具 它包含了一个项
  • 加密解密相关→EncryptUtils

    import android util Base64 import java io File import java io FileInputStream import java io IOException import java sec
  • SQL学习(二)初学SQL

    初学SQL有很多困惑 比如 学习SQL需不需要编写SQL语句 去哪里调试SQL语句 怎么创建表 有没有什么SQL的代码调试和编辑器 这些问题导致我们不知道从何下手 大概看了看网上对于SQL的介绍 明白是什么之后 再看了看基础的查询语句 但是
  • Echarts 折线图 自定义悬浮窗tooltip,读取params中的数据将小数显示为百分比并保留两位小数,日期只显示年月日

    在网上没有找到我需要的内容 悬浮窗数据一直显示为 Object Object 获取不到params中的相应内容 通过System out println map 获取到的后台数据格式为 treeMapData yield 0 9894 ti
  • JMeter安装和环境变量配置

    JAVA基础环境安装 下载Java Development Kit 下载地址 JDK官网下载 配置JDK环境变量 JDK 安装与环境变量配置请自行查询 JMeter下载 JMeter官网 解压JMeter 将下载后的文件进行解压 放置到指定
  • 拉格朗日插值定理

    拉格朗日插值法是一种函数逼近方法 通过已知的数据点构建一个多项式函数 该函数能够恰好经过这些数据点 它可以用于插值 即根据给定的离散数据点推断出未知函数在其它点上的取值 拉格朗日插值法的优点是计算简单 容易理解和实现 但是由于多项式次数越高
  • C++变量替换

    测试用例 4 xxx lyf ttt test ttt www yyy seeyou aa aaa x x x b b b
  • 上下文工程:基于 Github Copilot 的实时能力分析与思考

    上个月在计划为 AutoDev 添加多语言支持时候 发现 GitHub Copilot 的插件功能是语言无关的 通过 plugin xml 分析 便想研究一下它是如何使用 TreeSitter 的 可惜的是 直到最近才有空 研究一下它是如何
  • 【转】IE命令行参数

    k参数可以让IE工作在全屏方式下 slf参数会让IE连接到默认的主页 new开新的IE进程 channelband 收藏夹 nohome 无显示 blank空白页面也不显示 remote参数可以在Unix平台上启动另一个IE进程 v参数会显
  • springBoot实现统一结果封装、统一异常处理

    springBoot统一结果封装 统一异常处理 统一结果封装 目的 由于现在大部分公司项目都是前后端分离架构 为了联调方便统一后端数据返回格式 统一结果封装 实现 统一返回结果实体类 统一结果封装 Data public class R p
  • sqlite "replace into"的用法

    http blog sina com cn s blog 590be5290102vulh html 举例说明 建表并插入几条记录 CREATE TABLE test id INTEGER PRIMARY KEY name text age
  • springboot的脚手架搭建步骤

    SpringBoot脚手架搭建及运用 Max伏虎的博客 CSDN博客 springboot脚手架
  • Window 系统生成 Git SSH key

    当我们使用github或者bitbucket等仓库时我们有可能需要ssh认证 所以需要生成他的ssh key 1 首先你要安装git工具 下载地址 https git scm com downloads 2 右键鼠标 选中 Git Bash
  • VCRUNTIME140_1.dll丢失是怎么回事,如何修复VCRUNTIME140_1.dll缺失?

    VCRUNTIME140 1 dll是什么文件 它为啥会丢失呢 应该很多小伙伴对这问题都比较疑惑吧 毕竟有时候电脑突然弹出一个VCRUNTIME140 1 dll文件丢失 无法继续执行 面对这种提示都是一脸懵逼的 今天我们就来聊聊VCRUN
  • Kafka可视化平台EFAK搭建及使用

    文章目录 1 EFAK可视化平台介绍 2 搭建EFAK可视化平台 2 1 安装JDK环境 2 2 安装MySQL数据库 2 3 下载EAK二进制安装包并部署 2 4 配置EFAK连接Zookeeper集群 2 5 调整Eagle启动文件中的
  • 线程同步及互斥锁

    线程同步的概念 线程同步 指一个线程发出某一功能调用时 在没有得到结果之前 该调用不返回 同时其它线程为保证数据一致性 不能调用该功能 线程同步的例子 创建两个线程 让两个线程共享一个全局变量int number 然后让每个线程数5000次