C++ 错题本 MAC环境下 unique_lock try_lock_for函数爆红问题

下方是一个非常简单的,尝试使用unique_lock去尝试加锁的示例代码,在调用try_lock_for函数的时候爆红。这个函数本来就是按照编辑器提示点出来的,不可能没有这个方法 ,比较奇怪。

报错如图所示:

运行的时候编译器报错:no member named 'try_lock_for' in 'std::mutex'

代码如下:

cpp 复制代码
/**
 *如果直接调用 unique_lock<mutex> unique_lock(mtx);
  则会出现直接上锁的操作,因为默认就是加锁。但是我们如果要用到try lock for所指向的功能
  即:如果在拿资源的时候,资源已经被别的线程使用中,则会尝试等待指定的时间,一直获取锁,等到时间到了,代码无论如何都要解除阻塞继续执行。
  则用原先的构造方法难以实现。所以这样用需要用到第二种构造方法,来取消构造时加锁的操作
 */
void UniqueLock::testTryLockFor(){
    unique_lock<mutex> lock(mtx, std::defer_lock); //构造函数执行但是内部不加锁!
    //就给5秒的时间,如果加不了锁,那么5秒过后就会直接执行
    this_thread::sleep_for(chrono::seconds(5));
    // 问题出处,此处 try_lock_for 爆红
    lock.try_lock_for(std::chrono::seconds(5)); 
    for (int i = 0; i < 100000; ++i) {
        b++;
    }
}

问题分析

其实表面上原因解释非常简单,就是没有try_lock_for这个方法。楼主查了一下,这个方法是在C++11标准里添加的,楼主的版本也是C++11。版本上来讲是正确的。所以还得往别的方向查。

然后我们好好看报错内容,点击调用的代码,发现是,unique_lock这个文件中

内部维护的 mutex变量所属的类,它没有try_lock_for这个方法!嗯,没有这个方法,但源码中却有这么一行代码,让惯用java的楼主感觉震惊!总觉得没那么严谨。

然而这个方法用到了一个模板,楼主传入的类型为mutex类型,结果查看,的确,楼主传入的类型并没有实现 try_lock_for 函数。

但是!有的类型实现了!

一个叫 recursive_timed_mutex的类是支持try_lock_for函数的。所以:

将锁的类型改为 recursive_timed_mutex 类型

cpp 复制代码
/**
 *如果直接调用 unique_lock<mutex> unique_lock(mtx);
  则会出现直接上锁的操作,因为默认就是加锁。但是我们如果要用到try lock for所指向的功能
  即:如果在拿资源的时候,资源已经被别的线程使用中,则会尝试等待指定的时间,一直获取锁,等到时间到了,代码无论如何都要解除阻塞继续执行。
  则用原先的构造方法难以实现。所以这样用需要用到第二种构造方法,来取消构造时加锁的操作
 */
void UniqueLock::testTryLockFor(){
    // 解决,将传入的锁改为recursive_timed_mutex类型即可。
    unique_lock<recursive_timed_mutex> lock(recursive_time_mutex, std::defer_lock); //构造函数执行但是内部不加锁!
    //就给5秒的时间,如果加不了锁,那么5秒过后就会直接执行
    this_thread::sleep_for(chrono::seconds(5));
    lock.try_lock_for(std::chrono::seconds(5));
    for (int i = 0; i < 100000; ++i) {
        b++;
    }
}

总结及扩展

楼主是刚系统的学习C++, 是跟着一个视频写的,对于上述代码,视频中,用的的确是C++11, 用到的类的确仅仅就是mutex这个类型,就能全部跑通, 但楼主的代码就是不可以。

为什么呢?

直到楼主看源码注意到一行字,并且查了一下,发现了 LLVM 这个框架的存在。

老师的代码,不知道用的是什么版本的,但楼主的代码,#include 的时候,的确引入的是LLVM框架里的unique_lock 。 这个框架的源码,对mutex代码压根就是没有实现try_lock_for。但是好在它在recursive_timed_mutex类里实现了相关方法。所以才解了。
LLVM是个啥?为什么我的IDE点进去用的是这个库的代码,楼主Clion都没怎么设置。为什么Clion默认设置用LLVM的?

初学C++, 首先感觉,怎么这么乱!!!!

LLVM是什么

苹果公司的软硬件体系基本是用到了LLVM这个套件开发的。是一套用于构建和优化编译器的工具。也是创建一门新语言的利器。LLVM规范了源代码转向机器码这一复杂过程。

编译器

编译器是将人可理解的源代码,转变为可执行二进制文件的工具。

其编译根据代码的编译过程分为三个段, 前端, 中间优化, 后端。理论上讲三个阶段的边界是分明的。 但是实现的时候,却五花八门

下图为编译器三段图:

实际上随着语言种类的增加却实现成了这个鬼样子,下图中的每一条连线,都意味着经历了上图中的三段历程

上图可以看出,如果每个语言都编译成机器码的话,对于语言开发者,要开发一门新的语言,要懂得就是全套的,从看得懂的高级语言,到汇编指令,到机器码全部打通。这种全才还是少的,能在各方面集齐这些人,也是不容易的。 重点是,需要的人多,对事物的理解也不同,中间容易出问题。

如果有个专业的团队做专业的事, 把中间打通形成统一的规则,以后开发任何新兴语言,只需要遵守统一的规则,由这个中间件负责专业的转换成机器码,就稳健的多。

于是如图:

LLVM就干了这么一件事,作为一个中枢适配的存在。LLVM使用了一种语言无关的中间代码来表示高级代码,称为中间表示,也就是图中的 IR。就意味着,许多不同的语言,比如Rust, Ruby都能通过LLVM提供的工具链生成同样的IR,这样的话,就可以使用同一套工具进行分析和优化,之后再转换成某种特定架构的机器码。
所以如果您有兴趣打造自己的编程语言,可以学习一下这个。

LLVM

LLVM项目目前已经发展成为一个巨大的编译器相关的工具集合,全称为 Low Level Virtual Machine 。

想想,如果您的项目有不同的语言组成,编译的时候,可以采用针对语言进行单独编译,也可以用LLVM的特点,将所有支持IR相关协议的语言进行编译,那么这种情况下,LLVM就有优势了。

下图为LLVM对各项语言的支持原理。

其流程均是将各个语言解析为统一的IR, 之后LLVM对根据统一的IR来生成针对不同架构的机器码。

从图中也可以看出,Clang 编译器也是LLVM框架下的重要前端,其支持的语言为 C, C++, Objective-C以及其他语言。

楼主因为是MAC本子,配置的是Xcode软件自带的编译器, Xcode自带的编译器就是Clang编译器,是LLVM架构下的工具链。 所以楼主用clion编辑器编辑的时候,引入的代码是 LLVM架构中的代码。

总结

● C++有的语句,方法找不到,是因为方法根本就没有被实现,原因是编译器所带工具链库,实现方式不同导致,但基本上大差不差,大多能一样调用,出现不同的话,应该会找到替代的方式。

● LLVM是个很强悍的编译工具链,苹果公司有采用这套工具链。Xcode使用的Clang编译器,也是LLVM架构下的。Clang编译器以其友好的错误和警告信息著称,受到开发者喜爱。

相关推荐
wjs202410 分钟前
DOM CDATA
开发语言
Tingjct12 分钟前
【初阶数据结构-二叉树】
c语言·开发语言·数据结构·算法
猷咪38 分钟前
C++基础
开发语言·c++
IT·小灰灰39 分钟前
30行PHP,利用硅基流动API,网页客服瞬间上线
开发语言·人工智能·aigc·php
快点好好学习吧41 分钟前
phpize 依赖 php-config 获取 PHP 信息的庖丁解牛
android·开发语言·php
秦老师Q42 分钟前
php入门教程(超详细,一篇就够了!!!)
开发语言·mysql·php·db
烟锁池塘柳042 分钟前
解决Google Scholar “We‘re sorry... but your computer or network may be sending automated queries.”的问题
开发语言
是誰萆微了承諾42 分钟前
php 对接deepseek
android·开发语言·php
CSDN_RTKLIB1 小时前
WideCharToMultiByte与T2A
c++
2601_949868361 小时前
Flutter for OpenHarmony 电子合同签署App实战 - 已签合同实现
java·开发语言·flutter