目錄html
參考:ios
http://www.javashuo.com/article/p-fofmzcap-hk.htmlc++
https://en.cppreference.com/w/git
https://wizardforcel.gitbooks.io/cpp-11-faq/content/77.html編程
http://www.cplusplus.com/reference/promise
C++11 新標準中引入了四個頭文件來支持多線程編程,他們分別是
#include <bits/stdc++.h> #include <thread> using namespace std; void function_name() { cout << "hello world" << endl; } int main() { std::thread t(function_name); t.join(); return 0; }
std::thread 構造併發
注意:可被 joinable 的 thread 對象必須在他們銷燬以前被主線程 join 或者將其設置爲 detached.異步
其餘函數async
get_id | 獲取線程ID |
---|---|
joinable | 檢查線程是否能夠join |
join | join線程 |
detach | detach線程 |
swap | swap線程 |
native_handle | 返回native_handle |
hardware_concurrency[static] | 檢查硬件併發性 |
參考:https://en.cppreference.com/w/cpp/thread/thread/thread
#include <iostream> #include <utility> #include <thread> #include <chrono> void f1(int n) { for (int i = 0; i < 5; ++i) { std::cout << "Thread 1 executing\n"; ++n; std::this_thread::sleep_for(std::chrono::milliseconds(10)); } } void f2(int& n) { for (int i = 0; i < 5; ++i) { std::cout << "Thread 2 executing\n"; ++n; std::this_thread::sleep_for(std::chrono::milliseconds(10)); } } class foo { public: void bar() { for (int i = 0; i < 5; ++i) { std::cout << "Thread 3 executing\n"; ++n; std::this_thread::sleep_for(std::chrono::milliseconds(10)); } } int n = 0; }; int main() { int n = 0; foo f; std::thread t1; // t1 is not a thread std::thread t2(f1, n + 1); // pass by value std::thread t3(f2, std::ref(n)); // pass by reference std::thread t4(std::move(t3)); // t4 is now running f2(). t3 is no longer a thread std::thread t5(&foo::bar, &f); // t5 runs foo::bar() on object f t2.join(); t4.join(); t5.join(); std::cout << "Final value of n is " << n << '\n'; std::cout << "Final value of foo::n is " << f.n << '\n'; }
Thread 1 executing Thread 2 executing Thread 3 executing Thread 3 executing Thread 1 executing Thread 2 executing Thread 2 executing Thread 3 executing Thread 1 executing Thread 3 executing Thread 2 executing Thread 1 executing Thread 3 executing Thread 1 executing Thread 2 executing Final value of n is 5 Final value of foo::n is 5
std::thread t5(&foo::bar, &f); // t5 runs foo::bar() on object f
保留疑惑,函數名便是地址,加&仍是地址,可是看別人怎麼寫。
move (1) | thread& operator= (thread&& rhs) noexcept; |
---|---|
copy [deleted] (2) | thread& operator= (const thread&) = delete; |
Mutex 系列類(四種)
Lock 類(兩種)
其餘類型
函數
併發最大的問題就是對臨界區資源的訪問,主要是經過互斥量上鎖的方法解決。
http://www.cplusplus.com/reference/mutex/mutex/try_lock/ 具體細節看庫便可,下面解析一些常見的
主要用unique_lock,在構造函數上鎖,在析構函數解鎖,第一個參數爲互斥量,第二個是可選
https://en.cppreference.com/w/cpp/thread/lock_tag
#include <bits/stdc++.h> using namespace std; int main() { std::mutex my_mutex; std::unique_lock<std::mutex> lock(my_mutex); ///表示這個互斥量已經lock成功了,通知構造函數不用在lock了, my_mutex.lock(); ///必須先lock才能用 std::unique_lock<std::mutex> lock1(my_mutex, std::adopt_lock); ///後面會本身unlock() ///============================ ///嘗試鎖,沒鎖成功不阻塞, 前提互斥量不能被鎖定 std::unique_lock<std::mutex> lock2(my_mutex, std::try_to_lock); if(lock.owns_lock()) { ///拿到了鎖頭 } else { ///沒有拿到鎖頭 } ///============================ ///我沒加鎖,後面手動鎖,方便調用函數, 前提互斥量不能被鎖定 std::unique_lock<std::mutex> lock3(my_mutex, std::defer_lock); lock3.lock(); ///加鎖 lock3.unlock(); ///不加鎖 if(lock3.try_lock() == true) { ///拿到鎖頭了 } else { ///沒拿到 } ///釋放互斥量 std::mutex *m = lock3.release(); return 0; }
一個線程等待另外一個線程條件知足
void function_name() { unique_lock<mutex> lock(mutex1); ///能往下走,確定互斥量默認被鎖了,到wait。 ///第二個參數可選,沒寫默認false。true爲不堵塞,繼續走。 ///若是是false卡在這等待其餘線程的con.notify_one()的函數 ///注意notify_one的時候必須卡在wait的地方,不然喚醒失敗 ///notify_all() con.wait(lock, [] () { if(true) { return true; } return false; }); }
std::async啓動一個異步任務後,返回一個std::future訪問異步操做結果的機制
#include <bits/stdc++.h> #include <future> using namespace std; int mythread() { cout << "mythread = " << this_thread::get_id() << endl; return 5; } int main () { cout << "main = " << this_thread::get_id() << endl; ///壓根沒建立子線程,在主線程中作,視乎默認是這個 std::future<int>ret = std::async(std::launch::deferred, mythread); ///async 新線程在這裏開始 std::future<int>ret = std::async(std::launch::async, mythread); cout << ret.get(); ///卡在這裏等結果 return 0; }
用packaged_task打包線程,就多了一個能夠返回結果的future接口
#include <bits/stdc++.h> #include <future> #include <thread> using namespace std; int mythread() { cout << "mythread = " << this_thread::get_id() << endl; return 5; } int main () { ///std::packaged_task 打包可調用對象 std::packaged_task<int()>mypt(mythread); std::thread t1(std::ref(mypt)); t1.join(); std::future<int>res = mypt.get_future(); return 0; }
後續就能夠這麼用
/// vector<std::std::packaged_task<int()>> vec; ///不用移動語義可能會出問題 vec.push_back(std::move(mypt));