[转] c++11并发之std::thread

[转自 https://blog.csdn.net/liuker888/article/details/46848905#]

知识链接:

C++11 并发之std::mutex

C++11 并发之std::atomic

本文概要:

1、成员类型和成员函数。

2、std::thread 构造函数。

3、异步。

4、多线程传递参数。

5、join、detach。

6、获取CPU核心个数。

7、CPP原子变量与线程安全。

8、lambda与多线程。

9、时间等待相关问题。

10、线程功能拓展。

11、多线程可变参数。

12、线程交换。

13、线程移动。

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

 

1、成员类型和成员函数。

成员类型:

id
Thread id (public member type )                                       id
native_handle_type
Native handle type (public member type )

成员函数:

(constructor)
Construct thread (public member function )        构造函数
(destructor)
Thread destructor (public member function )      析构函数
operator=
Move-assign thread (public member function )  赋值重载
get_id
Get thread id (public member function )                获取线程id
joinable
Check if joinable (public member function )          判断线程是否可以加入等待
join
Join thread (public member function )                    加入等待
detach
Detach thread (public member function )              分离线程
swap
Swap threads (public member function )               线程交换
native_handle
Get native handle (public member function )       获取线程句柄
hardware_concurrency [static]
Detect hardware concurrency (public static member function )   检测硬件并发特性

Non-member overloads:

swap (thread)
Swap threads (function )

2、std::thread 构造函数。

如下表:

default (1)
thread() noexcept;
initialization(2)

template <class Fn, class... Args>   explicit thread (Fn&& fn, Args&&... args);
copy [deleted] (3)
thread (const thread&) = delete;
move [4]
hread (thread&& x) noexcept;

(1).默认构造函数,创建一个空的 thread 执行对象。

(2).初始化构造函数,创建一个 thread 对象,该 thread 对象可被 joinable,新产生的线程会调用 fn 函数,该函数的参数由 args 给出。

(3).拷贝构造函数(被禁用),意味着 thread 不可被拷贝构造。

(4).move 构造函数,move 构造函数,调用成功之后 x 不代表任何 thread 执行对象。

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

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

 1 <span style="font-size:12px;">#include<iostream>
 2 #include<thread>
 3 #include<chrono>
 4 using namespace std;
 5 void fun1(int n)  //初始化构造函数
 6 {
 7     cout << "Thread " << n << " executing\n";
 8     n += 10;
 9     this_thread::sleep_for(chrono::milliseconds(10));
10 }
11
12 void fun2(int & n) //拷贝构造函数
13 {
14     cout << "Thread " << n << " executing\n";
15     n += 20;
16     this_thread::sleep_for(chrono::milliseconds(10));
17 }
18
19 int main()
20 {
21     int n = 0;
22     thread t1;               //t1不是一个thread
23     thread t2(fun1, n + 1);  //按照值传递
24     t2.join();
25     cout << "n=" << n << ‘\n‘;
26     n = 10;
27     thread t3(fun2, ref(n)); //引用
28     thread t4(move(t3));     //t4执行t3,t3不是thread
29     t4.join();
30     cout << "n=" << n << ‘\n‘;
31     return 0;
32 }
33
34 运行结果:
35 Thread 1 executing
36 n=0
37 Thread 10 executing
38 n=30</span>

3、异步。

例如:

 1 <span style="font-size:12px;">#include<iostream>
 2 #include<thread>
 3 using namespace std;
 4 void show()
 5 {
 6     cout << "hello cplusplus!" << endl;
 7 }
 8 int main()
 9 {
10     //栈上
11     thread t1(show);   //根据函数初始化执行
12     thread t2(show);
13     thread t3(show);
14     //线程数组
15     thread th[3]{thread(show), thread(show), thread(show)};
16     //堆上
17     thread *pt1(new thread(show));
18     thread *pt2(new thread(show));
19     thread *pt3(new thread(show));
20     //线程指针数组
21     thread *pth(new thread[3]{thread(show), thread(show), thread(show)});
22     return 0;
23 }</span>

4、多线程传递参数。

例如:

 1 <span style="font-size:12px;">#include<iostream>
 2 #include<thread>
 3 using namespace std;
 4 void show(const char *str, const int id)
 5 {
 6     cout << "线程 " << id + 1 << " :" << str << endl;
 7 }
 8 int main()
 9 {
10     thread t1(show, "hello cplusplus!", 0);
11     thread t2(show, "你好,C++!", 1);
12     thread t3(show, "hello!", 2);
13     return 0;
14 }
15 运行结果:
16 线程 1线程 2 :你好,C++!线程 3 :hello!
17 :hello cplusplus!</span>

发现,线程 t1、t2、t3 都执行成功!

5、join、detach。

join例子如下:

 1 <span style="font-size:12px;">#include<iostream>
 2 #include<thread>
 3 #include<array>
 4 using namespace std;
 5 void show()
 6 {
 7     cout << "hello cplusplus!" << endl;
 8 }
 9 int main()
10 {
11     array<thread, 3>  threads = { thread(show), thread(show), thread(show) };
12     for (int i = 0; i < 3; i++)
13     {
14         cout << threads[i].joinable() << endl;//判断线程是否可以join
15         threads[i].join();//主线程等待当前线程执行完成再退出
16     }
17     return 0;
18 }
19 运行结果:
20 hello cplusplus!
21 hello cplusplus!
22 1
23 hello cplusplus!
24 1
25 1</span>

总结:

join 是让当前主线程等待所有的子线程执行完,才能退出。

detach例子如下:

 1 <span style="font-size:12px;">#include<iostream>
 2 #include<thread>
 3 using namespace std;
 4 void show()
 5 {
 6     cout << "hello cplusplus!" << endl;
 7 }
 8 int main()
 9 {
10     thread th(show);
11     //th.join();
12     th.detach();//脱离主线程的绑定,主线程挂了,子线程不报错,子线程执行完自动退出。
13     //detach以后,子线程会成为孤儿线程,线程之间将无法通信。
14     cout << th.joinable() << endl;
15     return 0;
16 }
17 运行结果:
18 hello cplusplus!
19 0</span>

结论:

线程 detach 脱离主线程的绑定,主线程挂了,子线程不报错,子线程执行完自动退出。

线程 detach以后,子线程会成为孤儿线程,线程之间将无法通信。

6、获取CPU核心个数。

例如:

 1 <span style="font-size:12px;">#include<iostream>
 2 #include<thread>
 3 using namespace std;
 4 int main()
 5 {
 6     auto n = thread::hardware_concurrency();//获取cpu核心个数
 7     cout << n << endl;
 8     return 0;
 9 }
10 运行结果:
11 8</span>

结论:

通过  thread::hardware_concurrency() 获取 CPU 核心的个数。

7、CPP原子变量与线程安全。

问题例如:

 1 <span style="font-size:12px;">#include<iostream>
 2 #include<thread>
 3 using namespace std;
 4 const int N = 100000000;
 5 int num = 0;
 6 void run()
 7 {
 8     for (int i = 0; i < N; i++)
 9     {
10         num++;
11     }
12 }
13 int main()
14 {
15     clock_t start = clock();
16     thread t1(run);
17     thread t2(run);
18     t1.join();
19     t2.join();
20     clock_t end = clock();
21     cout << "num=" << num << ",用时 " << end - start << " ms" << endl;
22     return 0;
23 }
24 运行结果:
25 num=143653419,用时 730 ms</span>

从上述代码执行的结果,发现结果并不是我们预计的200000000,这是由于线程之间发生冲突,从而导致结果不正确。

为了解决此问题,有以下方法:

(1)互斥量。

例如:

 1 <span style="font-size:12px;">#include<iostream>
 2 #include<thread>
 3 #include<mutex>
 4 using namespace std;
 5 const int N = 100000000;
 6 int num(0);
 7 mutex m;
 8 void run()
 9 {
10     for (int i = 0; i < N; i++)
11     {
12         m.lock();
13         num++;
14         m.unlock();
15     }
16 }
17
18 int main()
19 {
20     clock_t start = clock();
21     thread t1(run);
22     thread t2(run);
23     t1.join();
24     t2.join();
25     clock_t end = clock();
26     cout << "num=" << num << ",用时 " << end - start << " ms" << endl;
27     return 0;
28 }
29 运行结果:
30 num=200000000,用时 128323 ms</span>

不难发现,通过互斥量后运算结果正确,但是计算速度很慢,原因主要是互斥量加解锁需要时间。

互斥量详细内容 请参考C++11 并发之std::mutex

(2)原子变量。

例如:

 1 <span style="font-size:12px;">#include<iostream>
 2 #include<thread>
 3 #include<atomic>
 4 using namespace std;
 5 const int N = 100000000;
 6 atomic_int num{ 0 };//不会发生线程冲突,线程安全
 7
 8 void run()
 9 {
10     for (int i = 0; i < N; i++)
11     {
12         num++;
13     }
14 }
15 int main()
16 {
17     clock_t start = clock();
18     thread t1(run);
19     thread t2(run);
20     t1.join();
21     t2.join();
22     clock_t end = clock();
23     cout << "num=" << num << ",用时 " << end - start << " ms" << endl;
24     return 0;
25 }
26
27 运行结果:
28 num=200000000,用时 29732 ms</span>

不难发现,通过原子变量后运算结果正确,计算速度一般。

原子变量详细内容 请参考C++11 并发之std::atomic。

(3)加入 join 。

例如:

 1 <span style="font-size:12px;">#include<iostream>
 2 #include<thread>
 3 using namespace std;
 4 const int N = 100000000;
 5 int num = 0;
 6
 7 void run()
 8 {
 9     for (int i = 0; i < N; i++)
10     {
11         num++;
12     }
13 }
14 int main()
15 {
16     clock_t start = clock();
17     thread t1(run);
18     t1.join();
19     thread t2(run);
20     t2.join();
21     clock_t end = clock();
22     cout << "num=" << num << ",用时 " << end - start << " ms" << endl;
23     return 0;
24 }
25 运行结果:
26 num=200000000,用时 626 ms</span>

不难发现,通过原子变量后运算结果正确,计算速度也很理想。

8、lambda与多线程。

例如:

 1 <span style="font-size:12px;">#include<iostream>
 2 #include<thread>
 3 using namespace std;
 4 int main()
 5 {
 6     auto fun = [](const char *str) {cout << str << endl; };
 7     thread t1(fun, "hello world!");
 8     thread t2(fun, "hello beijing!");
 9     return 0;
10 }
11 运行结果:
12 hello world!
13 hello beijing!</span>

9、时间等待相关问题。

例如:

 1 <span style="font-size:12px;">#include<iostream>
 2 #include<thread>
 3 #include<chrono>
 4 using namespace std;
 5 int main()
 6 {
 7     thread th1([]()
 8     {
 9         //让线程等待3秒
10         this_thread::sleep_for(chrono::seconds(3));
11         //让cpu执行其他空闲的线程
12         this_thread::yield();
13         //线程id
14         cout << this_thread::get_id() << endl;
15     });
16     return 0;
17 }</span>

10、线程功能拓展。

例如:

 1 <span style="font-size:12px;">#include<iostream>
 2 #include<thread>
 3 using namespace std;
 4 class MyThread :public thread   //继承thread
 5 {
 6 public:
 7     //子类MyThread()继承thread()的构造函数
 8     MyThread() : thread()
 9     {
10
11     }
12     //MyThread()初始化构造函数
13     template<typename T, typename...Args>
14     MyThread(T&&func, Args&&...args) : thread(forward<T>(func), forward<Args>(args)...)
15     {
16     }
17     void showcmd(const char *str)  //运行system
18     {
19         system(str);
20     }
21 };
22 int main()
23 {
24     MyThread th1([]()
25     {
26         cout << "hello" << endl;
27     });
28     th1.showcmd("calc"); //运行calc
29     //lambda
30     MyThread th2([](const char * str)
31     {
32         cout << "hello" << str << endl;
33     }, " this is MyThread");
34     th2.showcmd("notepad");//运行notepad
35     return 0;
36 }
37 运行结果:
38 hello
39 //运行calc
40 hello this is MyThread
41 //运行notepad</span>

11、多线程可变参数。

例如:

 1 <span style="font-size:12px;">#include<iostream>
 2 #include<thread>
 3 #include<cstdarg>
 4 using namespace std;
 5 int show(const char *fun, ...)
 6 {
 7     va_list ap;//指针
 8     va_start(ap, fun);//开始
 9     vprintf(fun, ap);//调用
10     va_end(ap);
11         return 0;
12 }
13 int main()
14 {
15     thread t1(show, "%s    %d    %c    %f", "hello world!", 100, ‘A‘, 3.14159);
16     return 0;
17 }
18 运行结果:
19 hello world!    100    A    3.14159</span>

12、线程交换。

例如:

 1 <span style="font-size:12px;">#include<iostream>
 2 #include<thread>
 3 using namespace std;
 4 int main()
 5 {
 6     thread t1([]()
 7     {
 8         cout << "thread1" << endl;
 9     });
10     thread t2([]()
11     {
12         cout << "thread2" << endl;
13     });
14     cout << "thread1‘ id is " << t1.get_id() << endl;
15     cout << "thread2‘ id is " << t2.get_id() << endl;
16     cout << "swap after:" << endl;
17     swap(t1, t2);//线程交换
18     cout << "thread1‘ id is " << t1.get_id() << endl;
19     cout << "thread2‘ id is " << t2.get_id() << endl;
20     return 0;
21 }
22 运行结果:
23 thread1
24 thread2
25 thread1‘ id is 4836
26 thread2‘ id is 4724
27 swap after:
28 thread1‘ id is 4724
29 thread2‘ id is 4836</span>

两个线程通过 swap 进行交换。

13、线程移动。

例如:

 1 <span style="font-size:12px;">#include<iostream>
 2 #include<thread>
 3 using namespace std;
 4 int main()
 5 {
 6     thread t1([]()
 7     {
 8         cout << "thread1" << endl;
 9     });
10     cout << "thread1‘ id is " << t1.get_id() << endl;
11     thread t2 = move(t1);;
12     cout << "thread2‘ id is " << t2.get_id() << endl;
13     return 0;
14 }
15 运行结果:
16 thread
17 thread1‘ id is 5620
18 thread2‘ id is 5620</span>

原文地址:https://www.cnblogs.com/yi-mu-xi/p/10021112.html

时间: 2024-08-19 08:43:52

[转] c++11并发之std::thread的相关文章

C++11并发之std::mutex

知识链接: C++11并发之std::thread   本文概要: 1. 头文件. 2.std::mutex. 3.std::recursive_mutex. 4.std::time_mutex. 5.std::lock_guard 与 std::unique_lock. Mutex 又称互斥量,C++ 11中与 Mutex 相关的类(包括锁类型)和函数都声明在 #include 头文件中,所以如果你需要使用 std::mutex,就必须包含 #include 头文件. 1. 头文件. Mute

C++11 并发指南------std::thread 详解

参考: https://github.com/forhappy/Cplusplus-Concurrency-In-Practice/blob/master/zh/chapter3-Thread/Introduction-to-Thread.md#stdthread-%E8%AF%A6%E8%A7%A3 本节将详细介绍 std::thread 的用法. std::thread 在 <thread> 头文件中声明,因此使用 std::thread 需包含 <thread> 头文件. &

C++11多线程std::thread的简单使用

转自:http://blog.csdn.net/star530/article/details/24186783 在cocos2dx 2.0时代,我们使用的是pthread库,是一套用户级线程库,被广泛地使用在跨平台应用上.但在cocos2dx 3.0中并未发现有pthread的支持文件,原来c++11中已经拥有了一个更好用的用于线程操作的类std::thread.cocos2dx 3.0的版本默认是在vs2012版本,支持c++11的新特性,使用std::thread来创建线程简直方便. 下面

Cocos2dx 3.0 过渡篇(二十七)C++11多线程std::thread的简单使用(下)

本篇接上篇继续讲:上篇传送门:http://blog.csdn.net/star530/article/details/24186783 简单的东西我都说的几乎相同了,想挖点深的差点把自己给填进去. 以下实际演练一下.请同意我參考偶尔E往事的一篇线程的博客, 他用的是pThread.这里我就用std::thread. 1.售票孙鑫老师的C++和Java多线程售票也一直让我念念不忘(好吧,我承认我没看过).这里用cocos2d-x3.0和C++11的std::thread实现一个吧.总共同拥有10

mingw-w64线程模型:posix vs win32(posix允许使用c++11的std:: thread,但要带一个winpthreads,可能需要额外dll)

我正在安装 mingw-w64 on Windows,有两个选项: win32线程和posix线程. 我知道win32线程和pthreads之间的区别,但是我不明白这两个选项之间的区别. 我怀疑如果我选择了posix线程,它将阻止我调用像CreateThread这样的WinAPI函数. 似乎这个选项指定了哪个程序或者库将使用哪个线程 API,但通过什么? 由 GCC,libstdc++或者其他事物? 我发现:什么区别thread_posixs和 thread_win32 gcc Windows

C++11 std::thread在类的成员函数中的使用

#include <thread> #include <iostream> class Wrapper { public: void member1() { std::cout << "i am member1" << std::endl; } void member2(const char *arg1, unsigned arg2) { std::cout << "i am member2 and my first

c++11多线程记录1 -- std::thread

启动一个线程 话不多说,直接上代码 void func(); int main() { std::thread t(func); //这里就开始启动线程了 return 0; } void func() { std::cout << "Hello, " << std::this_thread::get_id() << std::endl; } 等待子线程结束 有时候开启一个子线程之后,父线程很快运行结束: 如果想要父线程做完自己的工作之后等待子线程运

C++——多线程编程(一)std::thread

(一)与C++11多线程相关的头文件 C++11 新标准中引入了四个头文件来支持多线程编程,他们分别是< atomic> ,< thread>,< mutex>,< condition_variable>和< future>. ?< atomic>:该头文主要声明了两个类, std::atomic 和 std::atomic_flag,另外还声明了一套 C 风格的原子类型和与 C 兼容的原子操作的函数. ?< thread>

c++11特性之std::thread--进阶二

继续C++11的std::thread之旅! 下面讨论如何给线程传递参数 这个例子是传递一个string #include <iostream> #include <thread> #include <string> void thread_function(std::string s) { std::cout << "thread function "; std::cout << "message is = &qu