簡介
thread 類表示單獨的執行線程。
一個已初始化的 thread 對象表示一條活躍的執行線程,且它是 joinable 的,有一個唯一的線程 id 。
一個默認構造的 thread 對象(未初始化)不是 joinable 的,且它的線程 id 和所有 non-joinable 的線程一樣。
一個 joinable 的線程通過移動、調用 join() 或 detach() 變爲 non-joinable 的。
創建線程
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; |
fn:可調用對象,包括函數指針、指向成員函數的指針、函數對象(重載了 operator()、閉包)。
args:傳給 fn 的參數。
// constructing threads
#include <iostream>
#include <atomic>
#include <thread>
#include <vector>
std::atomic<int> global_counter(0);
void increase_global(int n) { for (int i = 0; i < n; ++i) ++global_counter; }
void increase_reference(std::atomic<int>& variable, int n) { for (int i = 0; i < n; ++i) ++variable; }
struct C : std::atomic<int> {
C() : std::atomic<int>(0) {}
void increase_member(int n) {
for (int i = 0; i < n; ++i) fetch_add(1);
}
};
int main() {
std::vector<std::thread> threads;
std::cout << "increase global counter with 10 threads...\n";
for (int i = 1; i <= 10; ++i)
threads.push_back(std::thread(increase_global, 1000));
std::cout << "increase counter (foo) with 10 threads using reference...\n";
std::atomic<int> foo(0);
for (int i = 1; i <= 10; ++i)
threads.push_back(std::thread(increase_reference, std::ref(foo), 1000));
std::cout << "increase counter (bar) with 10 threads using member...\n";
C bar;
for (int i = 1; i <= 10; ++i)
threads.push_back(std::thread(&C::increase_member, std::ref(bar), 1000));
std::cout << "synchronizing all threads...\n";
for (auto& th : threads) th.join();
std::cout << "global_counter: " << global_counter << '\n';
std::cout << "foo: " << foo << '\n';
std::cout << "bar: " << bar << '\n';
return 0;
}
increase global counter using 10 threads...
increase counter (foo) with 10 threads using reference...
increase counter (bar) with 10 threads using member...
synchronizing all threads...
global_counter: 10000
foo: 10000
bar: 10000
移動
move (1) | thread& operator= (thread&& rhs) noexcept; |
---|---|
copy [deleted] (2) | thread& operator= (const thread&) = delete; |
// example for thread::operator=
#include <iostream>
#include <thread>
#include <chrono>
void pause_thread(int n) {
std::this_thread::sleep_for (std::chrono::seconds(n));
std::cout << "pause of " << n << " seconds ended\n";
}
int main() {
std::thread threads[5]; // default-constructed threads
std::cout << "Spawning 5 threads...\n";
for (int i=0; i<5; ++i)
threads[i] = std::thread(pause_thread,i+1); // move-assign threads
std::cout << "Done spawning threads. Now waiting for them to join:\n";
for (int i=0; i<5; ++i)
threads[i].join();
std::cout << "All threads joined!\n";
return 0;
}
Spawning 5 threads...
Done spawning threads. Now waiting for them to join:
pause of 1 seconds ended
pause of 2 seconds ended
pause of 3 seconds ended
pause of 4 seconds ended
pause of 5 seconds ended
All threads joined!
線程 ID
id get_id() const noexcept;
// thread::get_id / this_thread::get_id
#include <iostream>
#include <thread>
#include <chrono>
std::thread::id main_thread_id = std::this_thread::get_id();
void is_main_thread() {
if ( main_thread_id == std::this_thread::get_id() )
std::cout << "This is the main thread.\n";
else
std::cout << "This is not the main thread.\n";
}
int main() {
is_main_thread();
std::thread th (is_main_thread);
th.join();
}
This is the main thread.
This is not the main thread.
join
bool joinable() const noexcept;
線程是否爲 joinable 。
void join();
等待,直到線程終止才返回。
// example for thread::joinable and join
#include <iostream>
#include <thread>
void mythread() {
// do stuff...
}
int main() {
std::thread foo;
std::thread bar(mythread);
std::cout << "Joinable after construction:\n" << std::boolalpha;
std::cout << "foo: " << foo.joinable() << '\n';
std::cout << "bar: " << bar.joinable() << '\n';
if (foo.joinable()) foo.join();
if (bar.joinable()) bar.join();
std::cout << "Joinable after joining:\n" << std::boolalpha;
std::cout << "foo: " << foo.joinable() << '\n';
std::cout << "bar: " << bar.joinable() << '\n';
return 0;
}
Joinable after construction:
foo: false
bar: true
Joinable after joining:
foo: false
bar: false
detach
void detach();
將 thread 對象表示的線程和調用線程分離,之後,它們彼此獨立,各自執行。當兩個之一執行結束時,被分離的線程會釋放其資源。
#include <iostream>
#include <thread>
#include <chrono>
void pause_thread(int n) {
std::this_thread::sleep_for (std::chrono::seconds(n));
std::cout << "pause of " << n << " seconds ended\n";
}
int main() {
std::cout << "Spawning and detaching 3 threads...\n";
std::thread (pause_thread,1).detach();
std::thread (pause_thread,2).detach();
std::thread (pause_thread,3).detach();
std::cout << "Done spawning threads.\n";
std::cout << "(the main thread will now pause for 5 seconds)\n";
// give the detached threads time to finish (but not guaranteed!):
pause_thread(5);
return 0;
}
Spawning and detaching 3 threads...
Done spawning threads.
(the main thread will now pause for 5 seconds)
pause of 1 seconds ended
pause of 2 seconds ended
pause of 3 seconds ended
pause of 5 seconds ended
交換
成員函數 | void swap (thread& x) noexcept; |
---|---|
非成員函數 | void swap (thread& x, thread& y) noexcept; |
交換兩個 thread 對象的狀態。
// swap
#include <iostream>
#include <thread>
#include <chrono>
void pause_thread(int n) {
std::this_thread::sleep_for(std::chrono::seconds(n));
}
int main() {
std::thread th1(pause_thread, 1);
std::thread th2(pause_thread, 1);
std::cout << "before swap: " << std::endl;
std::cout << "thread1's id: " << th1.get_id() << std::endl;
std::cout << "thread2's id: " << th2.get_id() << std::endl;
th1.swap(th2);
std::cout << "\nafter swap: " << std::endl;
std::cout << "thread1's id: " << th1.get_id() << std::endl;
std::cout << "thread2's id: " << th2.get_id() << std::endl;
th1.join();
th2.join();
return 0;
}
before swap:
thread1's id: 4688
thread2's id: 5992
after swap:
thread1's id: 5992
thread2's id: 4688
支持的線程數
static unsigned hardware_concurrency() noexcept;
只是一個提示值,當該值不可計算時,它返回 0.
操作當前線程
std::this_thread 名稱空間中。
線程 ID
thread::id get_id() noexcept;
返回調用線程的線程 ID。
線程讓步
void yield() noexcept;
使調用線程讓步,即重新調度。
// this_thread::yield example
#include <iostream>
#include <thread>
#include <atomic>
std::atomic<bool> ready(false);
void count1m() {
while (!ready) { // wait until main() sets ready...
std::this_thread::yield();
}
for (volatile int i = 0; i < 1000000; ++i) {}
}
int main() {
std::thread th(count1m);
ready = true; // go!
th.join();
std::cout << '\n';
return 0;
}
線程休眠
睡到某一時刻 | template <class Clock, class Duration> void sleep_until (const chrono::time_point<Clock,Duration>& abs_time); |
---|---|
睡一段時間 | template <class Rep, class Period> void sleep_for (const chrono::duration<Rep,Period>& rel_time); |
// this_thread::sleep_until example
#include <iostream>
#include <iomanip>
#include <thread>
#include <chrono>
#include <ctime>
int main() {
using std::chrono::system_clock;
std::time_t tt = system_clock::to_time_t (system_clock::now());
struct std::tm * ptm = std::localtime(&tt);
std::cout << "Current time: " << std::put_time(ptm,"%X") << '\n';
std::cout << "Waiting for the next minute to begin...\n";
++ptm->tm_min; ptm->tm_sec=0;
std::this_thread::sleep_until (system_clock::from_time_t (mktime(ptm)));
std::cout << std::put_time(ptm,"%X") << " reached!\n";
return 0;
}
Current time: 11:52:36
Waiting for the next minute to begin...
11:53:00 reached!
// this_thread::sleep_for example
#include <iostream>
#include <thread>
#include <chrono>
int main() {
std::cout << "countdown:\n";
for (int i=3; i>0; --i) {
std::cout << i << std::endl;
std::this_thread::sleep_for (std::chrono::seconds(1));
}
std::cout << "Lift off!\n";
return 0;
}
countdown:
3
2
1
Lift off!