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 }
拷贝赋值和移动赋值操作:
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 }
成员函数 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 }
成员函数 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 }
成员函数 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 }
静态成员函数 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 }
成员函数 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 }
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 }
注意:通常应该使用 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 }
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 }