↓ 跳过正文
  1. Posts/

std::call_once && std::once_flag notes

·486 字·1 分钟

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

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

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

 1    std::shared_ptr<some_resource> resource_ptr;
 2    std::mutex resource_mutex;
 3    void foo()
 4    {
 5    std::unique_lock<std::mutex> lk(resource_mutex);
 6    if(!resource_ptr)
 7    {
 8    resource_ptr.reset(new some_resource);
 9    }
10    lk.unlock();
11    resource_ptr->do_something();
12    }

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

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

下面是两个例子:

 1    std::shared_ptr<some_resource> resource_ptr;
 2    std::once_flag resource_flag;
 3    b
 4    void init_resource()
 5    {
 6    resource_ptr.reset(new some_resource);
 7    }
 8    void foo()
 9    {
10    std::call_once(resource_flag,init_resource);
11    resource_ptr->do_something();
12    }
13
14
15
16
17    class X
18    {
19    private:
20    connection_info connection_details;
21    connection_handle connection;
22    std::once_flag connection_init_flag;
23    void open_connection()
24    {
25    connection=connection_manager.open(connection_details);
26    }
27    public:62
28    C HAPTER 3 Sharing data between threads
29    X(connection_info const& connection_details_):
30    connection_details(connection_details_)
31    {}
32    void send_data(data_packet const& data)
33    {
34    std::call_once(connection_init_flag,&X::open_connection,this);
35    connection.send_data(data);
36    }
37    data_packet receive_data()
38    {
39    std::call_once(connection_init_flag,&X::open_connection,this);
40    return connection.receive_data();
41    }
42    b
43    d
44    c
45    };

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

比如声明的一个static 变量。

参考资料:

std::call_once

once_flag

相关文章

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

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

c++11 function 与bind 学习笔记

·315 字·1 分钟
C++11 std::function 是一种通用、多态的函数封装,它的实例可以对任何可 以调用的目标实体进行存储、复制和调用操作 见下面的例子 1 /* *********************************************** 2 Author :111qqz 3 mail: renkuanze@sensetime.com 4 Created Time :2018年07月19日 星期四 17时41分00秒 5 File Name :bind.cpp 6 ************************************************ */ 7 #include <functional> 8 #include <iostream> 9 using namespace std; 10 float foo( int x,int y,int z){return x+y+z+1.;} 11 int main() 12 { 13 function<int(int,int)>func = foo; 14 int y = 10; 15 function<int(int)>fun = [&]( int value)->int 16 { 17 return 1+value+y; 18 }; 19 cout<<func(15,4,9)<<endl; 20 cout<<fun(8)<<endl; 21 return 0; 22 } std::bind 则是用来绑定函数调用的参数的,它解决的需求是我们有时候可 能并不一定能够一次性获得调用某个函数的全部参数,通过这个函数,我们可以将 部分调用参数提前绑定到函数身上成为一个新的对象,然后在参数齐全后,完成调 用

C++ 记录代码运行时间

·169 字·1 分钟
以前用的办法太老土啦 看到一个since C++11的方法,我觉得比较优雅 1 #include <iostream> 2 #include <chrono> 3 //#include <ratio> 4 #include <thread> 5 6 void f() 7 { 8 std::this_thread::sleep_for(std::chrono::seconds(1)); 9 } 10 11 int main() 12 { 13 auto t1 = std::chrono::high_resolution_clock::now(); 14 f(); 15 auto t2 = std::chrono::high_resolution_clock::now(); 16 17 // floating-point duration: no duration_cast needed 18 std::chrono::duration<double, std::milli> fp_ms = t2 - t1; 19 20 // integral duration: requires duration_cast 21 auto int_ms = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1); 22 23 // converting integral duration to integral duration of shorter divisible time unit: 24 // no duration_cast needed 25 std::chrono::duration<long, std::micro> int_usec = int_ms; 26 27 std::cout << "f() took " << fp_ms.count() << " ms, " 28 << "or " << int_ms.count() << " whole milliseconds " 29 << "(which is " << int_usec.count() << " whole microseconds)" << std::endl; 30 }