std::call_once && std::once_flag notes

多线程保护数据时,一种较为特殊的情况是只需要保护资源的初始化。

资源初始化一般遵循”lazy initialization”的原则,也就是在用到该资源最近的地方再初始化。

比较容易想到的办法是用std::mutex,将资源初始化的地方锁起来,如下:

这确实是一个办法。但是初始化时如果需要耗费比较多的时间,当有比较多的线程时,一个线程初始化时,其他线程会耗时间在不必要的等待上。

在c++11以后,我们可以使用std::once_flag和std::call_once来解决资源初始化时加锁的问题。比起显示调用std::mutex的好处是,资源消耗更少。

 

下面是两个例子:

或者更一般地,可以解决一类在多线程环境下保证某段代码只执行一次的问题。

比如声明的一个static 变量。

参考资料:

std::call_once

once_flag

 

 

 

[c++11 ]std::move 右值引用 转移语义 完美转发 notes

起因是在看<CplusplusConcurrencyInAction_PracticalMultithreading>,里面讲到转移一个std::thread的ownership提到了std::move.

之前[C++11 ] std::ref&&std::reference_wrapper notes 提到的情况是在我们想要用引用的时候却进行了拷贝,得到不符合期望的结果。现在的情况是,有些object或许是不支持拷贝构造的。比如std::unique_str,std::ifstream,这个时候如果我们需要传参数进去,就可以使用std::move来实现。比如下面这个例子:

当然这只是使用std::move的一种情形,即传递不允许拷贝构造的object作为参数。

另外,std::move可以更有效率地传递资源。内容之后补orz

实际上std::move()的作用是传进去一个object,返回这个object的右值引用(rvalue reference)

首先区分左值和右值,这其实是一个c语言中就有的概念(作为区分,右值引用是C++11中新引入的概念)

一般来说,右值是不能被取地址的值。在C++11之前,右值是不能被引用的。

语法上为了区分C++11之前的引用(也就是左值引用&),右值引用的符号为&&

那么为什么要引入“右值引用”这个概念? 主要有两个目的:完美转发(Perfect Forwarding)转移语义(Move Sementics)

转移语义可以将资源 ( 堆,系统对象等 ) 从一个对象转移到另一个对象,这样能够减少不必要的临时对象的创建、拷贝以及销毁。转移语义是和拷贝语义相对的,可以类比文件的剪切与拷贝,当我们将文件从一个目录拷贝到另一个目录时,速度比剪切慢很多。

完美转发,也叫精确传递,指的是“需要将一组参数原封不动的传递给另一个函数”。

原封不动的含义是说:数值不变,左值/右值属性不变,const/non-const属性不变。

在泛型函数中,这样的需求非常普遍。

比如下面这个例子:

在右值引用出现,模板的每个参数都必须重载两个类型,总的重载次数是指数级的orz,警察听了想打人

然而有了右值引用,不管模板右多少个参数,我们只需要定义一次,接受一个右值引用的参数,就能够将所有的参数类型原封不动的传递给目标函数。

 

那么最后说回std::move. std::move的作用就是传入左值,返回右值引用,从而使用右值引用带来的好处(节省资源,实现完美转发等)

 

 

 

 

参考资料:

[C++11 ] std::ref&&std::reference_wrapper notes

起因是在看《CplusplusConcurrencyInAction_PracticalMultithreading》的时候,里面讲到初始化std::thread的时候,如果thread funtion的参数列表中有引用,需要传入std::ref才可以得到符合预期的结果。

查阅发现std::ref是用来生成std::reference_wrapper。 按照 cppreference 上的话来说

std::reference_wrapper 是包装引用于可复制、可赋值对象的类模板。它常用作将容器存储入无法正常保有引用的标准容器(类似 std::vector )的机制。

用人话来说,就是有的时候一些地方(比如STL容器中传值,又比如std::bind)会默认使用复制,这可能与我们想使用引用的期望不符。

具体见下面的几个例子:

我们发现直接传进去的参数n1的值没有改变,而使用std::ref传进去的值的结果符合预期。

n1的值不符合预期的原因是,在调用std::bind的时候,会先将参数复制一份,然后传入函数f时,传入的不是在main函数中定义的n1的引用,而是对n1复制了一份得到的临时变量的引用。在函数f中对n1的修改只会使得n1的复制值与其保持一致,而不会改变n1.

下面是一个关于 std::reference_wrapper 的例子

 

最后我们回到开始,将参数在通过创建std::thread传给thread funtion的时候,参数默认情况下仍然是被拷贝了一份,与上面std::bind的情况类似,因此需要使用std::ref

 

参考资料:

 

 

 

[C++11] promise && future leanrning notes

std::promise and std::future

 

用人话就是,主线程传给附属线程一个promise Object,然后主线程想要获取附属线程set给promise Object的值(也就是该线程返回的某个结果),需要通过主线程中的promise object 得到对应的future object(每个promise 对应一个 future),然后调用future 的get方法。如果附属线程没有执行作为参数传入的promise的set方法去返回结果,那么程序就会block住。

 

参考资料:

C++11 Multithreading – Part 7: Condition Variables Explained

c++11 function 与bind 学习笔记

C++11 std::function 是一种通用、多态的函数封装,它的实例可以对任何可
以调用的目标实体进行存储、复制和调用操作

见下面的例子

std::bind 则是用来绑定函数调用的参数的,它解决的需求是我们有时候可
能并不一定能够一次性获得调用某个函数的全部参数,通过这个函数,我们可以将
部分调用参数提前绑定到函数身上成为一个新的对象,然后在参数齐全后,完成调

看下面的例子:

 

 

C++ 记录代码运行时间

以前用的办法太老土啦

看到一个since C++11的方法,我觉得比较优雅

 

c++11 学习笔记

昨天终于搞定了ycm对c++11的支持….

嘛,17都快出来了,我竟然连11都不会用。

不过突然把所有的11特性给我也没办法全部吸收。

所以在这里记录下用过的c++11的用法。

auto可以代替stl的一些容器中的iterator: