• [原]C++新标准之std::thread


    概览

    从C++11开始提供了线程的支持,终于可以方便的编写跨平台的线程代码了。除了std::thread类,还提供了许多其它便利同步的机制,本篇总结是C++11学习笔记系列的首篇总结。

    std::thread

    std::thread定义在<thread>中,提供了方便的创建线程的功能。

    类定义

    1. class thread 
    2. { 
    3. public
    4. thread() noexcept
    5. thread( thread&& other ) noexcept
    6. template< class Function, class... Args > 
    7. explicit thread( Function&& f, Args&&... args ); 
    8. thread(const thread&) = delete
    9. ~thread(); 
    10. thread& operator=( thread&& other ) noexcept
    11. bool joinable() const noexcept
    12. std::thread::id get_id() const noexcept
    13. native_handle_type native_handle()
    14. void join()
    15. void detach()
    16. void swap( thread& other ) noexcept
    17. static unsigned int hardware_concurrency() noexcept
    18. }; 

    从定义中我们可以得知:

    各个成员函数的简单介绍

    例子

    因为thread类比较简单,我们通过几个例子来学习。

    • 支持移动语义,但不支持拷贝语义
    1. #include <thread> 
    2. void some_function() {} 
    3. void some_other_function() {} 
    4. int main() 
    5. std::thread t1(some_function); // 构造一个thread对象t1 
    6. std::thread t2 = std::move(t1); // 把t1 move给另外一个thread对象t2,t1不再管理之前的线程了。 
    7. // 这句不需要std::move(),从临时变量进行移动是自动和隐式的。调用的是operator=(std::thread&&) 
    8. t1 = std::thread(some_other_function); 
    9. std::thread t3; 
    10. t3 = std::move(t2); // 把t2 move给t3 
    11. // 把t3 move给t1,非法。因为`t1`已经有了一个相关的线程,会调用`std::terminate()`来终止程序。 
    12. t1 = std::move(t3); 
    • 通过调用join()成员函数来等待线程结束
    1. #include <iostream> 
    2. #include <thread> 
    3. #include <chrono> 
    4.  
    5. void foo()  
    6. std::this_thread::sleep_for(std::chrono::seconds(1)); 
    7.  
    8. int main() 
    9. std::cout << "starting first helper... "
    10. std::thread helper1(foo)
    11. helper1.join(); 
    • 传递参数给线程函数
    1. void f(int i, std::string const& s)
    2. std::thread t(f, 3 "hello")

    注意:参数会以默认的方式被复制到内部存储空间,直到使用的时候才会转成对应的类型。

    下面的例子有问题吗?有什么问题?

    1. void f(int i, std::string const& s)
    2. void oops(int some_param) 
    3. char buffer[1024]; 
    4. sprintf(buffer, "%i", some_param); 
    5. std::thread t(f, 3, buffer)
    6. t.detach(); 

    局部变量buffer的指针会被传递给新线程,如果oops()buffer被转换成string之前退出,那么会导致未定义的行为。解决之道是在构造std::thread的时候传递string变量。std::thread t(f, 3, std::string(buffer));

    可以使用std::ref()来显示表明要传递引用,就像std::bind()那样。

    1. std::thread t(update_data_for_widget, w, std::ref(data))
    • 使用类的成员函数作为线程参数
    1. #include <thread> 
    2. #include <string> 
    3. class CRunner 
    4. { 
    5. public
    6. void run0(){} 
    7. void run1(int a) {} 
    8. void run2(int a, int b) const {} 
    9. int run3(int a, char b, const std::string& c) {return 0;} 
    10. int run4(int& a, double b, float c, char d) { ++a; return 0; } 
    11. static void run_static(int a) {} 
    12. }; 
    13.  
    14. int main() 
    15. CRunner runner; 
    16. int a = 0
    17. // 使用std::mem_fun,需要传指针 
    18. std::thread t0(std::mem_fun(&CRunner::run0), &runner)
    19. // 使用std::mem_fun_ref,可以传引用或副本 
    20. std::thread t1(std::mem_fun_ref(&CRunner::run1), std::ref(runner), 1)
    21. // std::thread t1(std::mem_fun_ref(&CRunner::run1), runner, 1); 
    22.  
    23. // 使用std::mem_fn,std::mem_fn支持多于一个参数的函数,std::mem_fun不支持。 
    24. std::thread t2(std::mem_fn(&CRunner::run2), std::ref(runner), 1, 2)
    25. // 使用std::bind + std::mem_fn 
    26. std::thread t3(std::bind(std::mem_fn(&CRunner::run3), &runner, 1, 2, "data"));  
    27. // 使用std::mem_fn,注意std::ref的用法,如果不用std::ref行不行? 
    28. std::thread t4(std::mem_fn(&CRunner::run4), &runner, std::ref(a), 2.2, 3.3f, 'd');  
    29. // 使用类的静态函数 
    30. std::thread t5(&CRunner::run_static, 1)
    31.  
    32. t0.join(); 
    33. t1.join(); 
    34. t2.join(); 
    35. t3.join(); 
    36. t4.join(); 
    37. t5.join(); 

    注:

    更多

    虽然在之前的例子中的函数有返回值,但是我们却不能获得,想获得返回值我们需要使用std::future,关于std::future的总结,后续会慢慢补充,敬请期待。

    参考资料

  • 相关阅读:
    python匿名函数与bif-第五天
    python函数-第四天
    python元组与序列-第三天
    idea激活码最新获取方法(idea2020激活码汇总)
    hbase shell操作之scan+filter
    hbase过滤及查看数据知识点-day02
    Hbase基本知识点总结
    Python列表-一个打了激素的数组(3)
    SQL 随记
    数据库链接失败,报用用户密码错误
  • 原文地址:https://www.cnblogs.com/bianchengnan/p/9459490.html
Copyright © 2020-2023  润新知