(leetcode1114) C++11线程同步机制(源码粗读)

2023-11-23 01:40

本文主要是介绍(leetcode1114) C++11线程同步机制(源码粗读),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

线程同步

同步,顾名思义就是齐步并进。异步,就是两个人各走各的不管对方。两个同步的线程要时不时停下来等等对方,比如说一个线程负责读磁盘、另一个线程负责解析文件内容,那么解析文件内容的线程就要等都读磁盘的线程把内容读出来才能解析。而异步的两个线程各自干自己的工作,不会因为对方状况而阻塞。

在实际工作中总是会需要一些并发的操作,比如最基本的,服务器总要同时维持很多连接吧。
比如你要记录当前的连接数,那么就要有一个全局的cnt,来一个连接就cnt++,断一个连接就cnt–。

但是在汇编层面cnt++这个操作可能长这样(我这里写的是mips):

lw $t1, 8($t0)
addi $t1, $t1, 1
sw $ t1, 8($t0)

所以到机器层面上一共要执行三条指令,万一执行到一半的时候因为什么中断切出去了(比如时钟中断之后直接进行了线程切换),那么这个被取出的cnt值就会随着换出的上下文被存起来,这个时候如果另一个指令又执行了cnt++,然后再切回来的时候,+1操作就成了基于原先的cnt而不是最新的cnt。所以最后cnt的值就比实际的要小。

解决这个问题的方法就是引入一些同步机制。比如互斥锁mutex,或者信号量semaphore。这些东西最终在机器层面上都是有支持的,比如可以设计一种不会被打断的一种原子操作,所谓原子操作就是不会切换上下文,处理器可以执行一条关中断的指令来暂时屏蔽中断来达成这种效果。

具体在硬件层面的东西我不是很熟悉,我只是个程序员,今天我想从软件层面上探索一下C++的stl库里实现的一些同步机制。

我用这个网站来测试我的程序:https://leetcode-cn.com/problems/print-in-order/submissions/

mutex

mutex这个词是从mutal exclusive造出来的,意思是互斥。假设有好几个线程尝试对其上锁,那么第一个上锁操作会成功,后面对其上锁的线程会被阻塞。当该锁被解锁的时候,被阻塞的线程的其中一个会被唤醒,并且该锁再次被上锁。所以同一时间只能由某一个线程拥有该锁,如果你把锁放在互斥代码段的开头和结尾,就相当同时只有一个线程能够执行互斥代码。
在这里插入图片描述
构造函数是无参的,然后lock函数是阻塞式的,try_lock是非阻塞式的,非阻塞式的方法返回一个bool值表示加锁是否成功。unclock就是解锁,文档说如果对未上锁的锁进行unlock是未定义的行为。

以下代码是在leetcode1114上可以通过测试的,这份代码依次打印first,second,third

class Foo {
public:std::mutex m2, m3;Foo() {m2.lock();m3.lock();}void first(function<void()> printFirst) {// printFirst() outputs "first". Do not change or remove this line.printFirst();m2.unlock();}void second(function<void()> printSecond) {// printSecond() outputs "second". Do not change or remove this line.m2.lock();printSecond();m3

这篇关于(leetcode1114) C++11线程同步机制(源码粗读)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/414420

相关文章

JAVA保证HashMap线程安全的几种方式

《JAVA保证HashMap线程安全的几种方式》HashMap是线程不安全的,这意味着如果多个线程并发地访问和修改同一个HashMap实例,可能会导致数据不一致和其他线程安全问题,本文主要介绍了JAV... 目录1. 使用 Collections.synchronizedMap2. 使用 Concurren

C++如何通过Qt反射机制实现数据类序列化

《C++如何通过Qt反射机制实现数据类序列化》在C++工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作,所以本文就来聊聊C++如何通过Qt反射机制实现数据类序列化吧... 目录设计预期设计思路代码实现使用方法在 C++ 工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作。由于数据类

Linux下如何使用C++获取硬件信息

《Linux下如何使用C++获取硬件信息》这篇文章主要为大家详细介绍了如何使用C++实现获取CPU,主板,磁盘,BIOS信息等硬件信息,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录方法获取CPU信息:读取"/proc/cpuinfo"文件获取磁盘信息:读取"/proc/diskstats"文

Java 正则表达式URL 匹配与源码全解析

《Java正则表达式URL匹配与源码全解析》在Web应用开发中,我们经常需要对URL进行格式验证,今天我们结合Java的Pattern和Matcher类,深入理解正则表达式在实际应用中... 目录1.正则表达式分解:2. 添加域名匹配 (2)3. 添加路径和查询参数匹配 (3) 4. 最终优化版本5.设计思

C++使用printf语句实现进制转换的示例代码

《C++使用printf语句实现进制转换的示例代码》在C语言中,printf函数可以直接实现部分进制转换功能,通过格式说明符(formatspecifier)快速输出不同进制的数值,下面给大家分享C+... 目录一、printf 原生支持的进制转换1. 十进制、八进制、十六进制转换2. 显示进制前缀3. 指

C++中初始化二维数组的几种常见方法

《C++中初始化二维数组的几种常见方法》本文详细介绍了在C++中初始化二维数组的不同方式,包括静态初始化、循环、全部为零、部分初始化、std::array和std::vector,以及std::vec... 目录1. 静态初始化2. 使用循环初始化3. 全部初始化为零4. 部分初始化5. 使用 std::a

SpringRetry重试机制之@Retryable注解与重试策略详解

《SpringRetry重试机制之@Retryable注解与重试策略详解》本文将详细介绍SpringRetry的重试机制,特别是@Retryable注解的使用及各种重试策略的配置,帮助开发者构建更加健... 目录引言一、SpringRetry基础知识二、启用SpringRetry三、@Retryable注解

SpringKafka错误处理(重试机制与死信队列)

《SpringKafka错误处理(重试机制与死信队列)》SpringKafka提供了全面的错误处理机制,通过灵活的重试策略和死信队列处理,下面就来介绍一下,具有一定的参考价值,感兴趣的可以了解一下... 目录引言一、Spring Kafka错误处理基础二、配置重试机制三、死信队列实现四、特定异常的处理策略五

C++ vector的常见用法超详细讲解

《C++vector的常见用法超详细讲解》:本文主要介绍C++vector的常见用法,包括C++中vector容器的定义、初始化方法、访问元素、常用函数及其时间复杂度,通过代码介绍的非常详细,... 目录1、vector的定义2、vector常用初始化方法1、使编程用花括号直接赋值2、使用圆括号赋值3、ve

如何高效移除C++关联容器中的元素

《如何高效移除C++关联容器中的元素》关联容器和顺序容器有着很大不同,关联容器中的元素是按照关键字来保存和访问的,而顺序容器中的元素是按它们在容器中的位置来顺序保存和访问的,本文介绍了如何高效移除C+... 目录一、简介二、移除给定位置的元素三、移除与特定键值等价的元素四、移除满足特android定条件的元