c++多线程基础1(thread)

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

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)
thread (thread&& x) noexcept;

 

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

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

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

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

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

代码:

 1 #include <iostream>
 2 #include <chrono>
 3 #include <thread>
 4 using namespace std;
 5 
 6 void fun1(int n) {
 7     for(int i = 0; i < 5; ++i) {
 8         cout << "Thread " << n << " executing\n";
 9         std::this_thread::sleep_for(std::chrono::milliseconds(10));
10     }
11 }
12 
13 void fun2(int &n) {
14     for(int i = 0; i < 5; ++i) {
15         cout << "Thread 2 executing\n";
16         ++n;
17         std::this_thread::sleep_for(std::chrono::milliseconds(10));
18     }
19 }
20 
21 int main() {
22     int n = 0;
23     std::thread t1;//t1 不是一个线程
24     std::thread t2(fun1, n + 1);//值传参
25     std::thread t3(fun2, std::ref(n));//引用传参
26     std::thread t4(std::move(t3));//将t3的资源转移到t4,此时t3不再是一个线程
27 
28     t2.join();
29     t4.join();
30 
31     cout << "Final valuw of n is " << n << '\n';
32 
33 // 输出:
34 // Thread Thread 2 executing
35 // 1 executing
36 // Thread 2 executing
37 // Thread 1 executing
38 // Thread 2 executing
39 // Thread 1 executing
40 // Thread 2 executing
41 // Thread 1 executing
42 // Thread 2 executing
43 // Thread 1 executing
44 // Final valuw of n is 5
45 
46     return 0;
47 }
View Code

 

拷贝赋值和移动赋值操作:

move (1)
thread& operator= (thread&& rhs) noexcept;
copy [deleted] (2)
thread& operator= (const thread&) = delete;

 

(1). move 赋值操作,如果当前对象不可 joinable,需要传递一个右值引用(rhs)给 move 赋值操作;如果当前对象可被 joinable,则 terminate() 报错。

(2). 拷贝赋值操作被禁用,thread 对象不可被拷贝

代码:

 1 #include <iostream>
 2 #include <thread>
 3 #include <chrono>
 4 using namespace std;
 5 
 6 void thread_task(int n) {
 7     std::this_thread::sleep_for(std::chrono::seconds(n));
 8     cout << "hello thread "
 9         << std::this_thread::get_id()
10         << " paused " << n << " seconds" << endl;
11 }
12 
13 int main(void) {
14     std::thread thread[5];
15     cout << "Spawning 5 threads...\n";
16     for(int i = 0; i < 5; ++i) {
17         thread[i] = std::thread(thread_task, i + 1);//创建一个临时对象,并将临时对象资源移动到thread[i]
18     }
19     // thread[0] = thread[1];//错误,拷贝赋值函数是 delete 的
20     cout << "Done wpawning threads! now wait fo them to join\n";
21     for(auto &t : thread) {
22         t.join();
23     }
24     cout << "all threads joind.\n";
25 
26 // 输出:
27 // Spawning 5 threads...
28 // Done wpawning threads! now wait fo them to join
29 // hello thread 2 paused 1 seconds
30 // hello thread 3 paused 2 seconds
31 // hello thread 4 paused 3 seconds
32 // hello thread 5 paused 4 seconds
33 // hello thread 6 paused 5 seconds
34 // all threads joind.
35 
36     return 0;
37 }
View Code

 

成员函数 joinable:

用于检测线程是否 joinable

joinable : 代表该线程是可执行线程。

not-joinable :通常一下几种情况会导致线程成为 not-joinable

     1) 由 thread 的缺省构造函数构造而成 (thread()没有参数)。

     2) 该 thread 被 move 过(包括 move 构造和 move 赋值)

     3) 该线程调用过 join 或者 detach

代码:

 1 #include <iostream>
 2 #include <thread>
 3 #include <chrono>
 4 using namespace std;
 5 
 6 void foo() {
 7     std::this_thread::sleep_for(std::chrono::seconds(1));
 8 }
 9 
10 int main(void) {
11     std::thread t;
12     cout << t.joinable() << endl;//0
13 
14     t = std::thread(foo);//调用移动构造函数
15     cout << t.joinable() << endl;//1
16 
17     t.join();
18     cout << t.joinable() << endl;//0
19 
20     return 0;
21 }
View Code

 

成员函数 get_id:

标识与 *this 关联的线程的 std::thread::id 类型值。若无关联的线程,则返回默认构造的 std::thread::id 

代码:

 1 #include <iostream>
 2 #include <thread>
 3 #include <chrono>
 4 using namespace std;
 5 
 6 void foo() {
 7     std::this_thread::sleep_for(std::chrono::seconds(1));
 8 }
 9 
10 int main(void) {
11     std::thread t0;
12     std::thread::id t0_id = t0.get_id();
13 
14     std::thread t1(foo);
15     std::thread::id t1_id = t1.get_id();
16 
17     std::thread t2(foo);
18     std::thread::id t2_id = t2.get_id();
19 
20     cout << "t0's id: " << t0_id << "\n";
21     cout << "t1's id: " << t1_id << "\n";
22     cout << "t2's id: " << t2_id << "\n";
23 
24     t1.join();
25     t2.join();
26 
27 // 输出:
28 // t0's id: thread::id of a non-executing thread
29 // t1's id: 2
30 // t2's id: 3
31     return 0;
32 }
View Code

 

成员函数 native_handle:

用于获得与操作系统相关的原生线程句柄

代码:

 1 #include <thread>
 2 #include <mutex>
 3 #include <iostream>
 4 #include <chrono>
 5 #include <cstring>
 6 #include <pthread.h>
 7 using namespace std;
 8 
 9 std::mutex iomutex;
10 
11 void f(int num) {
12     std::this_thread::sleep_for(std::chrono::seconds(1));
13 
14     sched_param sch;
15     int policy;
16     pthread_getschedparam(pthread_self(), &policy, &sch);
17     std::lock_guard<std::mutex> lk(iostream);
18     cout << "thread " << num << " is executing at priority "
19         << sch.sched_priority << '\n';
20 }
21 
22 int main(void) {
23     std::thread t1(f, 1), t2(f, 2);
24  
25     sched_param sch;
26     int policy; 
27     pthread_getschedparam(t1.native_handle(), &policy, &sch);
28     sch.sched_priority = 20;
29     if (pthread_setschedparam(t1.native_handle(), SCHED_FIFO, &sch)) {
30         std::cout << "Failed to setschedparam: " << std::strerror(errno) << '\n';
31     }
32 
33     t1.join();
34     t2.join();
35 
36     return 0;
37 }
View Code

 

静态成员函数 hardware_concurrency:

支持的并发线程数。若值非良定义或不可计算,则返回 0​ 

代码:

 1 #include <iostream>
 2 #include <thread>
 3 using namespace std;
 4 
 5 int main(void) {
 6     unsigned int n = std::thread::hardware_concurrency();
 7     cout << n << endl;//4
 8 
 9     return 0;
10 }
View Code

 

成员函数 jion 和 detach:

http://blog.csdn.net/xibeichengf/article/details/71173543

当thread::join()函数被调用后,调用它的线程会被block,直到线程的执行被完成。基本上,这是一种可以用来知道一个线程已结束的机制。当thread::join()返回时,OS的执行的线程已经完成,C++线程对象可以被销毁

当thread::detach()函数被调用后,执行的线程从线程对象中被分离,已不再被一个线程对象所表达--这是两个独立的事情。C++线程对象可以被销毁,同时OS执行的线程可以继续

jion 样例代码:

 1 #include <iostream>
 2 #include <thread>
 3 #include <array>
 4 using namespace std;
 5 
 6 void show() {
 7     cout << "hello cplusplus\n";
 8 }
 9 
10 int main(void) {
11     array<thread, 3> threads = {thread(show), thread(show), thread(show)};
12     for(int i = 0; i < 3; ++i) {
13         cout << threads[i].joinable() << endl;//判断当前线程是否可以 join
14         threads[i].join();//主线程等待当前子线程完成才退出
15     }
16 
17 // 输出:
18 // hello cplusplus
19 // 1hello cplusplus
20 // hello cplusplus
21 
22 // 1
23 // 1
24 
25     return 0;
26 }
View Code

detach 样例代码:

 1 #include <iostream>
 2 #include <thread>
 3 #include <chrono>
 4 using namespace std;
 5 
 6 void pause_thread(int n) {
 7     std::this_thread::sleep_for(std::chrono::seconds(n));
 8     cout << "pause of " << n << " seconds ended\n";
 9 }
10 
11 int main(void) {
12     cout << "Spawning and detaching 3 threads...\n";
13     std::thread(pause_thread, 1).detach();//将执行的线程从线程对象中被分离
14     std::thread(pause_thread, 2).detach();
15     std::thread(pause_thread, 3).detach();
16     cout << "(the main thread will now pause for 5 seconds)\n";
17     pause_thread(5);
18 
19 // 输出:
20 // Spawning and detaching 3 threads...
21 // (the main thread will now pause for 5 seconds)
22 // pause of 1 seconds ended
23 // pause of 2 seconds ended
24 // pause of 3 seconds ended
25 // pause of 5 seconds ended
26 
27     return 0;
28 }
View Code

注意:通常应该使用 join,除非你需要更灵活并且想要独立地提供一种同步机制来等待线程完成,在这种情况下你应该使用detach

如果父线程先于子线程结束,那么子线程将在父线程结束的同时被迫结束

thread::join() 会清理子线程相关的内存空间,此后 thread object 将不再和这个子线程相关了,即 thread object 不再 joinable 了,所以 join 对于一个子线程来说只可以被调用一次

如果一个 C++ 线程对象当销毁时仍然可以被 join,会抛出异常

 

成员函数 swap:

void swap( thread& other noexcept;

 

互换二个 thread 对象的底层句柄

代码:

 1 #include <iostream>
 2 #include <thread>
 3 #include <chrono>
 4 using namespace std;
 5 
 6 void foo() {
 7     std::this_thread::sleep_for(std::chrono::seconds(1));
 8 }
 9 
10 void bar() {
11     std::this_thread::sleep_for(std::chrono::seconds(1));
12 }
13 
14 int main(void) {
15     std::thread t1(foo);
16     std::thread t2(bar);
17 
18     cout << t1.get_id() << endl;
19     cout << t2.get_id() << endl;
20 
21     std::swap(t1, t2);
22 
23     cout << "===" << endl;
24     cout << t1.get_id() << endl;
25     cout << t2.get_id() << endl;
26 
27     t1.swap(t2);
28 
29     cout << "---" << endl;
30     cout << t1.get_id() << endl;
31     cout << t2.get_id() << endl;
32 
33     t1.join();
34     t2.join();
35 
36 // 输出:
37 // 2
38 // 3
39 // ===
40 // 3
41 // 2
42 // ---
43 // 2
44 // 3
45 
46     return 0;
47 }
View Code

 

std::swap

void swap( thread &lhs, thread &rhs noexcept;

为 std::thread 特化 std::swap 算法。交换 lhs 与 rhs 的状态。等效地调用 lhs.swap(rhs

代码:

 1 #include <iostream>
 2 #include <thread>
 3 #include <chrono>
 4 using namespace std;
 5 
 6 void foo() {
 7     std::this_thread::sleep_for(std::chrono::seconds(1));
 8 }
 9 
10 void bar() {
11     std::this_thread::sleep_for(std::chrono::seconds(1));
12 }
13 
14 int main(void) {
15     std::thread t1(foo);
16     std::thread t2(bar);
17 
18     cout << t1.get_id() << endl;
19     cout << t2.get_id() << endl;
20 
21     std::swap(t1, t2);
22 
23     cout << "===" << endl;
24     cout << t1.get_id() << endl;
25     cout << t2.get_id() << endl;
26 
27     t1.swap(t2);
28 
29     cout << "---" << endl;
30     cout << t1.get_id() << endl;
31     cout << t2.get_id() << endl;
32 
33     t1.join();
34     t2.join();
35 
36 // 输出:
37 // 2
38 // 3
39 // ===
40 // 3
41 // 2
42 // ---
43 // 2
44 // 3
45 
46     return 0;
47 }
View Code

 

posted @ 2018-03-06 22:28  geloutingyu  阅读(624)  评论(0编辑  收藏  举报