下方是一个非常简单的,尝试使用unique_lock去尝试加锁的示例代码,在调用try_lock_for函数的时候爆红。这个函数本来就是按照编辑器提示点出来的,不可能没有这个方法 ,比较奇怪。
报错如图所示:
运行的时候编译器报错:no member named 'try_lock_for' in 'std::mutex'
代码如下:
/**
*如果直接调用 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 类型
/**
*如果直接调用 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编译器以其友好的错误和警告信息著称,受到开发者喜爱。
领取专属 10元无门槛券
私享最新 技术干货