參考鏈接:
線程支持庫:https://zh.cppreference.com/w/cpp/thread 若能懂此鏈接,下面都不用看
1. https://blog.csdn.net/coolwriter/article/details/79883253
2. https://blog.csdn.net/coolwriter/article/details/79884298
thread:構造線程
#include <iostream> // std::cout #include <thread> // std::thread void thr_function1() { for (int i = 0; i != 10; ++i) { std::cout << "thread 1 print " << i << std::endl; } } void thr_function2(int n) { std::cout << "thread 1 print " << n << std::endl; } int main() { std::thread t1(thr_function1); // spawn new thread that calls foo() std::thread t2(thr_function2, 111); // spawn new thread that calls bar(0) std::cout << "main, foo and bar now execute concurrently...\n"; // synchronize threads: t1.join(); // pauses until first finishes 主線程等待t1線程結束 t2.join(); // pauses until second finishes 主線程等待t2線程結束 std::cout << "thread 1 and htread 2 completed.\n"; return 0; }
class thread
member: http://www.cplusplus.com/reference/thread/thread/ Member types get_id //Thread id (public member type ) native_handle_type //Native handle type (public member type ) Member functions: Construct thread (public member function ) Thread destructor (public member function ) operator= // Move-assign thread (public member function ) get_id // Get thread id (public member function ) 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 )
多線程變量安全
方式一: 原子操作
方式二: std::mutex 互斥量
std::mutex 互斥量: https://zh.cppreference.com/w/cpp/thread/mutex
#include <iostream> // std::cout #include <thread> // std::thread #include <mutex> // std::mutex std::mutex mtx; // mutex for critical section void print_block(int n, char c) { // critical section (exclusive access to std::cout signaled by locking mtx): // mtx.try_lock //嘗試鎖定互斥,若互斥不可用,則返回 mtx.lock(); //鎖定互斥,若互斥不可用則阻塞 for (int i = 0; i<n; ++i) { std::cout << c; } std::cout << '\n'; mtx.unlock(); //解開互斥 } int main() { std::thread th1(print_block, 50, '*'); std::thread th2(print_block, 50, '$'); th1.join(); th2.join(); return 0; }
mutex類4種
std::mutex,最基本的 Mutex 類。
std::recursive_mutex,遞歸 Mutex 類。
std::time_mutex,定時 Mutex 類。
std::recursive_timed_mutex,定時遞歸 Mutex 類。
recursive_mutex: https://zh.cppreference.com/w/cpp/thread/recursive_mutex
std::recursive_mutex 與 std::mutex一樣,也是一種可以被上鎖的對象,但是和 std::mutex 不同的是,std::recursive_mutex 允許同一個線程對互斥量多次上鎖(即遞歸上鎖),
來獲得對互斥量對象的多層所有權,std::recursive_mutex 釋放互斥量時需要調用與該鎖層次深度相同次數的 unlock(),可理解為 lock() 次數和 unlock() 次數相同,除此之外,
std::recursive_mutex 的特性和 std::mutex 大致相同。
time_mutex: //https://zh.cppreference.com/w/cpp/thread/timed_mutex
std::time_mutex 比 std::mutex 多了兩個成員函數:
try_lock_for(): //嘗試鎖定互斥,若互斥在指定的時限時期中不可用則返回
try_lock_until(): //嘗試鎖定互斥,若直至抵達指定時間點互斥不可用則返回
#include <iostream> // std::cout #include <chrono> // std::chrono::milliseconds #include <thread> // std::thread #include <mutex> // std::timed_mutex std::timed_mutex mtx; void fireworks() { // waiting to get a lock: each thread prints "-" every 200ms: while (!mtx.try_lock_for(std::chrono::milliseconds(200))) { std::cout << "-"; } // got a lock! - wait for 1s, then this thread prints "*" std::this_thread::sleep_for(std::chrono::milliseconds(1000)); std::cout << "*\n"; mtx.unlock(); } int main () { std::thread threads[10]; // spawn 10 threads: for (int i=0; i<10; ++i) threads[i] = std::thread(fireworks); for (auto& th : threads) th.join(); return 0; }
Lock 類(兩種)
std::lock_guard: //https://zh.cppreference.com/w/cpp/thread/lock_guard
與 Mutex RAII 相關,方便線程對互斥量上鎖。 //https://zh.cppreference.com/w/cpp/thread/lock_guard
*值得注意的是,lock_guard 對象並不負責管理 Mutex 對象的生命周期,lock_guard 對象只是簡化了 Mutex 對象的上鎖和解鎖操作,
***: 方便線程對互斥量上鎖,即在某個 lock_guard 對象的聲明周期內,它所管理的鎖對象會一直保持上鎖狀態;
***: 而 lock_guard 的生命周期結束之后,它所管理的鎖對象會被解鎖。
#include <iostream> // std::cout #include <thread> // std::thread #include <mutex> // std::mutex, std::lock_guard, std::adopt_lock std::mutex mtx; // mutex for critical section void print_thread_id(int id) { mtx.lock(); std::lock_guard<std::mutex> lck(mtx, std::adopt_lock); //= mtx.lock() 且在lck 析構時,mtk.unlock std::cout << "thread #" << id << '\n'; } int main() { std::thread threads[10]; // spawn 10 threads: for (int i = 0; i<10; ++i) threads[i] = std::thread(print_thread_id, i + 1); for (auto& th : threads) th.join(); return 0; }
**** scope_lock:構造時是否加鎖是可選的(不加鎖時假定當前線程已經獲得鎖的所有權),析構時自動釋放鎖,所有權不可轉移,對象生存期內不允許手動加鎖和釋放鎖。
std::unique_lock: //https://zh.cppreference.com/w/cpp/thread/unique_lock
與 Mutex RAII 相關,方便線程對互斥量上鎖,但提供了更好的上鎖和解鎖控制。
類 unique_lock 是通用互斥包裝器,允許延遲鎖定、鎖定的有時限嘗試、遞歸鎖定、所有權轉移和與條件變量一同使用。
unique_lock比lock_guard使用更加靈活,功能更加強大。
使用unique_lock需要付出更多的時間、性能成本。所以能用lock_guard時,用lock_guard
class LogFile { std::mutex _mu; ofstream f; public: LogFile() { f.open("log.txt"); } ~LogFile() { f.close(); } void shared_print(string msg, int id) { std::unique_lock<std::mutex> guard(_mu);//如果 guard(_mu, std::defer_lock); 表示不上鎖 //do something 1 guard.unlock(); //臨時解鎖 //do something 2 guard.lock(); //繼續上鎖 // do something 3 f << msg << id << endl; cout << msg << id << endl; // 結束時析構guard會臨時解鎖 // 這句話可要可不要,不寫,析構的時候也會自動執行 // guard.ulock(); } };
condition_variable
類是同步原語 //https://zh.cppreference.com/w/cpp/thread/condition_variable
能用於阻塞一個線程,或同時阻塞多個線程,直至另一線程修改共享變量(條件)並通知 condition_variable 。
當 std::condition_variable 對象的某個 wait 函數被調用的時候,它使用 std::unique_lock(通過 std::mutex) 來鎖住當前線程。當前線程會一直被阻塞,直到另外一個線程在相同的 std::condition_variable 對象上調用了 notification 函數來喚醒當前線程。
#include <iostream> // std::cout #include <thread> // std::thread #include <mutex> // std::mutex, std::unique_lock #include <condition_variable> // std::condition_variable std::mutex mtx; // 全局互斥鎖. std::condition_variable cv; // 全局條件變量. bool ready = false; // 全局標志位. void do_print_id(int id) { std::unique_lock <std::mutex> lck(mtx); while (!ready) // 如果標志位不為 true, 則等待... cv.wait(lck); // 當前線程被阻塞, 當全局標志位變為 true 之后,此外還有 wait for ,wait until 等語句 // 線程被喚醒, 繼續往下執行打印線程編號id. std::cout << "thread " << id << '\n'; } void go() { std::unique_lock <std::mutex> lck(mtx); ready = true; // 設置全局標志位為 true. cv.notify_all(); // 喚醒所有線程. //notify_one 通知一個等待的線程 } int main() { std::thread threads[10]; // spawn 10 threads: for (int i = 0; i < 10; ++i) threads[i] = std::thread(do_print_id, i); std::cout << "10 threads ready to race...\n"; go(); // go! for (auto & th:threads) th.join(); return 0; }
結果:
10 threads ready to race...
thread 1
thread 0
thread 2
thread 3
thread 4
thread 5
thread 6
thread 7
thread 8
thread 9