博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C++11 并发指南------std::thread 详解
阅读量:7211 次
发布时间:2019-06-29

本文共 11886 字,大约阅读时间需要 39 分钟。

参考:

 

本节将详细介绍 std::thread 的用法。

std::thread 在 <thread> 头文件中声明,因此使用 std::thread 需包含 <thread> 头文件。

<thread> 头文件摘要

<thread> 头文件声明了 std::thread 线程类及 std::swap (交换两个线程对象)辅助函数。另外命名空间 std::this_thread 也声明在 <thread> 头文件中。下面是 C++11 标准所定义的 <thread> 头文件摘要:

参见 N3242=11-0012 草案第 30.3 节 Threads(p1133)。

namespace std {    #define __STDCPP_THREADS__ __cplusplus    class thread;    void swap(thread& x, thread& y);    namespace this_thread {        thread::id get_id();        void yield();        template 
void sleep_until(const chrono::time_point
& abs_time); template
void sleep_for(const chrono::duration
& rel_time); } }

<thread> 头文件主要声明了 std::thread 类,另外在 std::this_thread 命名空间中声明了get_idyieldsleep_until 以及 sleep_for 等辅助函数,本章稍微会详细介绍 std::thread 类及相关函数。

std::thread 类摘要

std::thread 代表了一个线程对象,C++11 标准声明如下:

namespace std {    class thread {        public:            // 类型声明:            class id;            typedef implementation-defined native_handle_type;            // 构造函数、拷贝构造函数和析构函数声明:            thread() noexcept;            template 
explicit thread(F&& f, Args&&... args); ~thread(); thread(const thread&) = delete; thread(thread&&) noexcept; thread& operator=(const thread&) = delete; thread& operator=(thread&&) noexcept; // 成员函数声明: void swap(thread&) noexcept; bool joinable() const noexcept; void join(); void detach(); id get_id() const noexcept; native_handle_type native_handle(); // 静态成员函数声明: static unsigned hardware_concurrency() noexcept; };}

std::thread 中主要声明三类函数:(1). 构造函数、拷贝构造函数及析构函数;(2). 成员函数;(3). 静态成员函数。另外,std::thread::id 表示线程 ID,同时 C++11 声明如下:

namespace std {    class thread::id {        public:            id() noexcept;    };    bool operator==(thread::id x, thread::id y) noexcept;    bool operator!=(thread::id x, thread::id y) noexcept;    bool operator<(thread::id x, thread::id y) noexcept;    bool operator<=(thread::id x, thread::id y) noexcept;    bool operator>(thread::id x, thread::id y) noexcept;    bool operator>=(thread::id x, thread::id y) noexcept;    template
basic_ostream
& operator<< (basic_ostream
& out, thread::id id); // Hash 支持 template
struct hash; template <> struct hash
;}

std::thread 详解

std::thread 构造和赋值

std::thread 构造函数

默认构造函数 (1) thread() noexcept;
初始化构造函数 (2) template <class Fn, class... Args>
explicit thread(Fn&& fn, Args&&... args);
拷贝构造函数 [deleted] (3) thread(const thread&) = delete;
Move 构造函数 (4) thread(thread&& x) noexcept;
  1. 默认构造函数(1),创建一个空的 std::thread 执行对象。
  2. 初始化构造函数(2),创建一个 std::thread 对象,该 std::thread 对象可被 joinable,新产生的线程会调用 fn 函数,该函数的参数由 args 给出。
  3. 拷贝构造函数(被禁用)(3),意味着 std::thread 对象不可拷贝构造。
  4. Move 构造函数(4),move 构造函数(move 语义是 C++11 新出现的概念,详见附录),调用成功之后 x 不代表任何std::thread 执行对象。

注意:可被 joinable 的 std::thread 对象必须在他们销毁之前被主线程 join 或者将其设置为 detached.

std::thread 各种构造函数例子如下():

#include 
#include
#include
#include
#include
#include
void f1(int n){ for (int i = 0; i < 5; ++i) { std::cout << "Thread " << n << " executing\n"; std::this_thread::sleep_for(std::chrono::milliseconds(10)); }}void f2(int& n){ for (int i = 0; i < 5; ++i) { std::cout << "Thread 2 executing\n"; ++n; std::this_thread::sleep_for(std::chrono::milliseconds(10)); }}int main(){ int n = 0; std::thread t1; // t1 is not a thread std::thread t2(f1, n + 1); // pass by value std::thread t3(f2, std::ref(n)); // pass by reference std::thread t4(std::move(t3)); // t4 is now running f2(). t3 is no longer a thread t2.join(); t4.join(); std::cout << "Final value of n is " << n << '\n';}

std::thread 赋值操作

Move 赋值操作 (1) thread& operator=(thread&& rhs) noexcept;
拷贝赋值操作 [deleted] (2) thread& operator=(const thread&) = delete;
  1. Move 赋值操作(1),如果当前对象不可 joinable,需要传递一个右值引用(rhs)给 move 赋值操作;如果当前对象可被joinable,则会调用 terminate() 报错。
  2. 拷贝赋值操作(2),被禁用,因此 std::thread 对象不可拷贝赋值。

请看下面的例子:

#include 
#include
#include
// std::chrono::seconds#include
// std::cout#include
// std::thread, std::this_thread::sleep_forvoid thread_task(int n) { std::this_thread::sleep_for(std::chrono::seconds(n)); std::cout << "hello thread " << std::this_thread::get_id() << " paused " << n << " seconds" << std::endl;}int main(int argc, const char *argv[]){ std::thread threads[5]; std::cout << "Spawning 5 threads...\n"; for (int i = 0; i < 5; i++) { threads[i] = std::thread(thread_task, i + 1); } std::cout << "Done spawning threads! Now wait for them to join\n"; for (auto& t: threads) { t.join(); } std::cout << "All threads joined.\n"; return EXIT_SUCCESS;}

其他成员函数

本小节例子来自 

  • get_id: 获取线程 ID,返回一个类型为 std::thread::id 的对象。请看下面例子:

    #include 
    #include
    #include
    void foo(){ std::this_thread::sleep_for(std::chrono::seconds(1));}int main(){ std::thread t1(foo); std::thread::id t1_id = t1.get_id(); std::thread t2(foo); std::thread::id t2_id = t2.get_id(); std::cout << "t1's id: " << t1_id << '\n'; std::cout << "t2's id: " << t2_id << '\n'; t1.join(); t2.join();}
  • joinable: 检查线程是否可被 join。检查当前的线程对象是否表示了一个活动的执行线程,由默认构造函数创建的线程是不能被 join 的。另外,如果某个线程 已经执行完任务,但是没有被 join 的话,该线程依然会被认为是一个活动的执行线程,因此也是可以被 join 的。

    #include 
    #include
    #include
    void foo(){ std::this_thread::sleep_for(std::chrono::seconds(1));}int main(){ std::thread t; std::cout << "before starting, joinable: " << t.joinable() << '\n'; t = std::thread(foo); std::cout << "after starting, joinable: " << t.joinable() << '\n'; t.join();}
  • join: Join 线程,调用该函数会阻塞当前线程,直到由 *this 所标示的线程执行完毕 join 才返回。

    #include 
    #include
    #include
    void foo(){ // simulate expensive operation std::this_thread::sleep_for(std::chrono::seconds(1));}void bar(){ // simulate expensive operation std::this_thread::sleep_for(std::chrono::seconds(1));}int main(){ std::cout << "starting first helper...\n"; std::thread helper1(foo); std::cout << "starting second helper...\n"; std::thread helper2(bar); std::cout << "waiting for helpers to finish..." << std::endl; helper1.join(); helper2.join(); std::cout << "done!\n";}
  • detach: Detach 线程。 将当前线程对象所代表的执行实例与该线程对象分离,使得线程的执行可以单独进行。一旦线程执行完毕,它所分配的资源将会被释放。

调用 detach 函数之后:

  1. *this 不再代表任何的线程执行实例。
  2. joinable() == false
  3. get_id() == std::thread::id()

另外,如果出错或者 joinable() == false,则会抛出 std::system_error.

#include 
#include
#include
void independentThread() { std::cout << "Starting concurrent thread.\n"; std::this_thread::sleep_for(std::chrono::seconds(2)); std::cout << "Exiting concurrent thread.\n"; } void threadCaller() { std::cout << "Starting thread caller.\n"; std::thread t(independentThread); t.detach(); std::this_thread::sleep_for(std::chrono::seconds(1)); std::cout << "Exiting thread caller.\n"; } int main() { threadCaller(); std::this_thread::sleep_for(std::chrono::seconds(5)); }
  • swap: Swap 线程,交换两个线程对象所代表的底层句柄(underlying handles)。

    #include 
    #include
    #include
    void foo(){ std::this_thread::sleep_for(std::chrono::seconds(1));}void bar(){ std::this_thread::sleep_for(std::chrono::seconds(1));}int main(){ std::thread t1(foo); std::thread t2(bar); std::cout << "thread 1 id: " << t1.get_id() << std::endl; std::cout << "thread 2 id: " << t2.get_id() << std::endl; std::swap(t1, t2); std::cout << "after std::swap(t1, t2):" << std::endl; std::cout << "thread 1 id: " << t1.get_id() << std::endl; std::cout << "thread 2 id: " << t2.get_id() << std::endl; t1.swap(t2); std::cout << "after t1.swap(t2):" << std::endl; std::cout << "thread 1 id: " << t1.get_id() << std::endl; std::cout << "thread 2 id: " << t2.get_id() << std::endl; t1.join(); t2.join();}

执行结果如下:

thread 1 id: 1892thread 2 id: 2584after std::swap(t1, t2):thread 1 id: 2584thread 2 id: 1892after t1.swap(t2):thread 1 id: 1892thread 2 id: 2584
  • native_handle: 返回 native handle(由于 std::thread 的实现和操作系统相关,因此该函数返回与 std::thread 具体实现相关的线程句柄,例如在符合 Posix 标准的平台下(如 Unix/Linux)是 Pthread 库)。

    #include 
    #include
    #include
    #include
    #include
    std::mutex iomutex;void f(int num){ std::this_thread::sleep_for(std::chrono::seconds(1)); sched_param sch; int policy; pthread_getschedparam(pthread_self(), &policy, &sch); std::lock_guard
    lk(iomutex); std::cout << "Thread " << num << " is executing at priority " << sch.sched_priority << '\n';}int main(){ std::thread t1(f, 1), t2(f, 2); sched_param sch; int policy; pthread_getschedparam(t1.native_handle(), &policy, &sch); sch.sched_priority = 20; if(pthread_setschedparam(t1.native_handle(), SCHED_FIFO, &sch)) { std::cout << "Failed to setschedparam: " << std::strerror(errno) << '\n'; } t1.join(); t2.join();}

执行结果如下:

Thread 2 is executing at priority 0Thread 1 is executing at priority 20
  • hardware_concurrency [static]: 检测硬件并发特性,返回当前平台的线程实现所支持的线程并发数目,但返回值仅仅只作为系统提示(hint)。

    #include 
    #include
    int main() { unsigned int n = std::thread::hardware_concurrency(); std::cout << n << " concurrent threads are supported.\n";}

std::this_thread 命名空间中相关辅助函数介绍

  • get_id: 获取线程 ID。

    #include 
    #include
    #include
    #include
    std::mutex g_display_mutex;void foo(){ std::thread::id this_id = std::this_thread::get_id(); g_display_mutex.lock(); std::cout << "thread " << this_id << " sleeping...\n"; g_display_mutex.unlock(); std::this_thread::sleep_for(std::chrono::seconds(1));}int main(){ std::thread t1(foo); std::thread t2(foo); t1.join(); t2.join();}
  • yield: 当前线程放弃执行,操作系统调度另一线程继续执行。

    #include 
    #include
    #include
    // "busy sleep" while suggesting that other threads run // for a small amount of timevoid little_sleep(std::chrono::microseconds us){ auto start = std::chrono::high_resolution_clock::now(); auto end = start + us; do { std::this_thread::yield(); } while (std::chrono::high_resolution_clock::now() < end);}int main(){ auto start = std::chrono::high_resolution_clock::now(); little_sleep(std::chrono::microseconds(100)); auto elapsed = std::chrono::high_resolution_clock::now() - start; std::cout << "waited for " << std::chrono::duration_cast
    (elapsed).count() << " microseconds\n";}
  • sleep_until: 线程休眠至某个指定的时刻(time point),该线程才被重新唤醒。

    template< class Clock, class Duration >void sleep_until( const std::chrono::time_point
    & sleep_time );
  • sleep_for: 线程休眠某个指定的时间片(time span),该线程才被重新唤醒,不过由于线程调度等原因,实际休眠时间可能比sleep_duration 所表示的时间片更长。

    template< class Rep, class Period >void sleep_for( const std::chrono::duration
    & sleep_duration );#include
    #include
    #include
    int main(){ std::cout << "Hello waiter" << std::endl; std::chrono::milliseconds dura( 2000 ); std::this_thread::sleep_for( dura ); std::cout << "Waited 2000 ms\n";}

执行结果如下:

Hello waiterWaited 2000 ms

转载地址:http://khrum.baihongyu.com/

你可能感兴趣的文章
MapReduce1和Yarn的工作机制
查看>>
awk 以列为域提取文件内容
查看>>
NEC中标里斯本智慧城市项目 助力城市整体数字化变革
查看>>
[转] 大规模服务设计部署经验谈
查看>>
Debian手动修改ip地址
查看>>
Realm的简单使用
查看>>
zabbix使用zabbix 数据库做数据分表
查看>>
Oracle 11g dataguard三种模式以及实时查询(Real-time query)功能设置
查看>>
exchange 2013 lesson 6 CAS HA installing
查看>>
Groovy中的闭包
查看>>
Alibaba Cloud Launches Dual-mode SSD to Optimize Hyper-scale Infrastructure Performance
查看>>
数字签名和数字证书详解
查看>>
用来代替SQUID的软件VARNISH
查看>>
每天学一点Scala之 伴生类和伴生对象
查看>>
http反向代理调度算法追朔
查看>>
做门户网站 个人站长的新好出路
查看>>
sql中exists,not exists的用法
查看>>
CentOS6.5更改ssh端口问题
查看>>
11g默认审计选项
查看>>
Where Did That New Exchange 2010 Mailbox Go?
查看>>