1.C++多線程初步:ios
#include <iostream> #include <thread> #include <Windows.h> using namespace std; void run() { MessageBoxA(0, "hello world", "hello china", 0); } void main0101() { //同步(阻塞) run(); run(); run(); cin.get(); } void main0102() { //並行,異步,非阻塞 thread t1(run); //根據函數初始化並執行,t1在棧上 thread t2(run); thread t3(run); thread t4(run); cin.get(); } void main0103() { //並行,異步,非阻塞 //thread t[5]{ run,run,run,run,run }; //error C2440: 「初始化」: 沒法從「void (__cdecl *)(void)」轉換爲「std::thread」 thread t[5]{ thread(run),thread(run), thread(run), thread(run), thread(run) }; //初始化線程數組(線程池) cin.get(); } void main0104() { //堆上 thread *pthread1(new thread(run)); thread *pthread2(new thread(run)); thread *pthread3(new thread(run)); cin.get(); } void main() { //堆上開闢了線程數組 thread *pthread1(new thread[5]{ thread(run),thread(run), thread(run), thread(run), thread(run) }); cin.get(); }
2. 線程凍結與解凍調試:數組
#include <iostream> #include <thread> #include <Windows.h> #include <cstdlib> using namespace std; void test() { int i = 0; while (1) { cout << ++i << endl; Sleep(1000); } } void main() { thread *p(new thread(test)); //堆上 system("pause"); system("pause"); system("pause"); system("pause"); cin.get(); }
3. 多線程傳參:promise
#include <iostream> #include <thread> #include <Windows.h> using namespace std; void showmsg(const char *str1, const char *str2) { MessageBoxA(0, str1, str2, 0); } void main() { thread th1(showmsg, "1", "1"); thread th2(showmsg, "111", "111"); thread th3(showmsg, "222", "222"); cin.get(); }
4. 多線程的join 和detach:安全
#include <iostream> #include <thread> #include <array> #include <Windows.h> using namespace std; //join讓當前主線程等待全部子線程執行完成才能退出 //detach脫離主線程的綁定,主線程退出的時候,不影響子線程。 void show() { MessageBoxA(0, "1", "1", 0); } void main0401() { array<thread, 3> threads{ thread(show),thread(show),thread(show) }; for (int i = 0; i < 3; i++) { cout << threads[i].joinable() << endl; //判斷是否能夠join threads[i].join(); //主線程等待子線程執行完成再退出 } auto n = thread::hardware_concurrency(); //獲取CPU是幾核 cout << n << endl; cin.get(); } void main() { thread th(show); //th.join(); th.detach(); //脫離主線程,主線程掛了不報錯 //detach之後線程沒法通訊 th.joinable(); }
5. 原子變量與線程安全:多線程
#include <iostream> #include <thread> #include <mutex> //互斥量 #include <atomic> //原子變量 using namespace std; //線程安全,多線程訪問不衝突就是線程安全,衝突則不安全 //int num = 0; //mutex m; //互斥,加鎖解鎖浪費時間 atomic_int num(0); //原子變量不會發生線程衝突,屬於線程安全 void run() { for (int i = 0; i < 10000000; i++) { //m.lock(); num++; //m.unlock(); } } void main() { clock_t start = clock(); thread th1(run); thread th2(run); th1.join(); th2.join(); clock_t end = clock(); cout << num << endl; cout << end - start << "ms" << endl; cin.get(); } //全局變量,會發生衝突,結果不正確,速度快 //mutex,結果正確,速度慢 //atomic,結果正確,速度比mutex快
6. lambda 表達式與多線程:異步
#include <iostream> #include <thread> #include <Windows.h> #include <chrono> using namespace std; void main0701() { //auto fun = []() {MessageBoxA(0, "1", "2", 0); }; //thread th1(fun); //thread th2(fun); thread th1([]() {MessageBoxA(0, "11", "22", 0); }); thread th2([]() {MessageBoxA(0, "11", "22", 0); }); cin.get(); } void main() { //thread th1([]() {cout << this_thread::get_id() << endl; }); //獲取當前線程的id //thread th2([]() {cout << this_thread::get_id() << endl; }); thread th1([]() { this_thread::sleep_for(chrono::seconds(3)); //等待3秒 this_thread::yield(); //讓CPU先執行其餘線程,空閒了再執行我 cout << this_thread::get_id() << endl; //獲取當前線程的id //this_thread::sleep_until(); //某個時刻到來以前一直等待 }); thread th2([]() { this_thread::sleep_for(chrono::seconds(10)); //等待10秒 cout << this_thread::get_id() << endl; }); cin.get(); }
7. 僞函數與多線程:async
(1)僞函數概念:函數
#include <iostream> using namespace std; struct func { void operator ()() //僞函數,能夠將對象名當作函數名來使用 { cout << "hello china hello cpp" << endl; } void operator ()(int i) //僞函數,能夠將對象名當作函數名來使用 { cout << "hello china hello cpp! " << i << endl; } }; void main() { func f1; f1(); func f2; f2(2); cin.get(); }
(2)僞函數與多線程:this
#include <iostream> #include <thread> #include <Windows.h> using namespace std; struct MyStruct { MyStruct() { cout << "create" << endl; } ~MyStruct() { cout << "end" << endl; } void operator ()() //對象名當作函數名使用,重載了(),但()只適用於當前結構體對象 { MessageBoxA(0, "111", "222", 0); } }; void main() { MyStruct go1; thread t1(go1); MyStruct go2; thread t2(go2); //MyStruct()是構造函數,建立一個臨時對象,匿名對象 //MyStruct()(); //thread t3(MyStruct());//匿名的對象,不適合做爲多線程參數,銷燬太快 //MyStruct *p = new MyStruct; MyStruct *p = new MyStruct();//多一個()就是構造函數 cin.get(); }
8. 成員函數構建多線程:atom
#include <iostream> #include <thread> #include <Windows.h> using namespace std; struct fun { void run1() { MessageBoxA(0, "12345", "ABCDE", 0); cout << "hello china" << endl; } void run2(const char *str) { MessageBoxA(0, str, str, 0); cout << "hello china" << endl; } }; void main() { //fun *p(nullptr); //p->run1(); //空類指針能夠引用沒有調用內部變量的成員函數 fun fun1; //&fun::run引用成員函數 thread th1(&fun::run1, fun1); thread th2(&fun::run1, fun1); thread th3(&fun::run2, fun1,"run2-1"); thread th4(&fun::run2, fun1, "run2-2"); cin.get(); }
9. 多線程通訊future:
#include <iostream> #include <thread> #include <future> #include <string> #include <cstdlib> using namespace std; void main0401() { string str1("12345"); string str2("678910"); string str3(str1 + str2); //C++風格的字符串 cout << str3 << endl; cin.get(); } promise<string>val; //全局通訊變量 void main() { thread th1([]() { future<string> fu = val.get_future();//獲取將來的狀態 cout << "等待中..." << endl; cout << fu.get() << endl; }); thread th2([]() { system("pause"); val.set_value("I love CPP"); system("pause"); }); th1.join(); th2.join(); }
10. 基於繼承的多線程:
#include <iostream> #include <thread> using namespace std; class zhangthread :public thread //C++代碼重用-->繼承 { public: zhangthread() :thread() //子類調父類的構造函數 { } template <typename T, typename...Args> //子類調父類的構造函數,可變參數的構造 zhangthread(T && func,Args &&...args):thread( forward<T>(func), forward<Args>(args)... ) { } void run(const char *cmd) //新增的功能 { system(cmd); } }; void main() { zhangthread t1([](){cout << "hello this is Zhang"<<endl;}); t1.run("calc"); zhangthread t2([](int num) {cout << "hello this is Zhang"<<num<<endl; },100 ); t2.run("notepad"); cin.get(); }
11. 條件變量:
#include <iostream> #include <thread> #include <mutex> #include <condition_variable> //條件變量 using namespace std; //線程通訊,結合mutex //一個線程,多個線程處於等待,通知一個或通知多個 mutex m; //線程互相排斥 condition_variable cv; //線程通訊 void main() { thread **th = new thread * [10];//開闢線程的指針數組 for (int i = 0; i < 10; i++) { th[i] = new thread([](int index) { unique_lock<mutex> lck(m); //鎖定 cv.wait_for(lck, chrono::hours(1000)); //一直等待 cout << index << endl; //打印編號 } , i ); //傳遞參數 this_thread::sleep_for(chrono::milliseconds(100)); //錯開 } for (int i = 0; i < 10; i++) { lock_guard<mutex> lckg(m);//解鎖嚮導 cv.notify_one(); //挨個通知 } for (int i = 0; i < 10; i++) { th[i]->join(); delete th[i]; } delete[]th; //釋放指針數組 cin.get(); }
12. 獲取線程的結果:
#include <iostream> #include <thread> #include <future>//線程未來結果 #include <chrono>//時間 #include <mutex> using namespace std; mutex g_m; void main() { auto run = [=](int index)->int { lock_guard<mutex> lckg(g_m); //加鎖 cout << this_thread::get_id() << " " << index << endl; //獲取線程id this_thread::sleep_for(chrono::seconds(10)); //等待10秒 return index * 1024; //返回結果 }; packaged_task<int(int)> pt1(run); packaged_task<int(int)> pt2(run); //建立兩個任務包 thread t1([&]() {pt1(2); }); thread t2([&]() {pt2(3); }); //開啓線程 cout << pt1.get_future().get() << endl; cout << pt2.get_future().get() << endl; //獲取結果 t1.join(); t2.join(); cin.get(); }
13. 可變參數實現多線程:
#include <iostream> #include <cstdarg> #include <thread> using namespace std; //可變參數 int go(const char *fmt, ...) { va_list ap; //第一個數據(指針) va_start(ap, fmt); //開始 vprintf(fmt, ap); //調用 va_end(ap); //結束 return 0; } void main() { thread th(go, "%sABCD%d____%c____%x", "12345abc", 123, 'A', 256); cin.get(); }
14. 多線程實現並行計算:
#include <iostream> #include <thread> #include <future> #include <vector> #include <cstdlib> using namespace std; #define COUNT 1000000 //線程函數: int add(vector<int> *arr, int start, int count) { static mutex m; //靜態局部變量,只會初始化一次 int sum(0);//保存結果 for (int i = 0; i < count; i++) { sum += (*arr)[start + i];//實現累加 } { //此處僅僅是計算過程當中的顯示,更清楚查看 lock_guard<mutex> lckg(m);//加鎖,不讓其餘線程干涉 cout << "thread" << this_thread::get_id() << ",count=" << count << ",sum=" << sum << endl; } return sum; } void main() { vector<int> data(COUNT); //數組,100萬的大小 for (int i = 0; i < COUNT; i++) { data[i] = i % 1000; //0-999 } vector< future<int> > result;//結果數組 int cpus = thread::hardware_concurrency();//CPU核心的個數 for (int i = 0; i < cpus * 2; i++) { //1000 10= 100 * 10 //1000 9 = 1000 - 111*8 int batch_each = COUNT / (cpus * 2); if (i == (cpus * 2) - 1) { batch_each = COUNT - COUNT / (cpus * 2)*i;//最後一個承擔的多一點 } //不斷壓入結果 result.push_back(async(add, &data, i*batch_each, batch_each));//async直接返回結果 } //彙總 int lastresult(0); for (int i = 0; i < cpus * 2; i++) { lastresult += result[i].get();//彙總結果,累加 } cout << "lastresule=" << lastresult << endl; cin.get(); }