C++多線程快速入門(一):基本常用操作

目錄

    • case1:創建線程1 join、detach
    • case2:創建線程2 線程傳參 傳值或者傳引用
    • case3:創建線程 線程傳參 functional object作為參數
    • case4:觀察多線程程序加速計算
    • case5:future + get 獲取并發結果
    • case6:互斥鎖
    • case7:std::lock_guard 類模板

case1:創建線程1 join、detach

創建線程,并等該線程執行完畢,并且打印兩個線程的id

#include <iostream>
#include <thread>
using namespace std;
void func() {cout << "hello , this is my thread, thread id is " << this_thread::get_id() << endl;
}
int main() {thread th = thread(func);th.join();cout << "this is main thread and its id is " << this_thread::get_id() << endl;
}

執行結果如下:

C:\Users\LENOVO\CLionProjects\untitled\cmake-build-debug\untitled.exe
hello , this is my thread, thread id is 2
this is main thread and its id is 1Process finished with exit code 0

使用detach,放棄對該線程的控制:

#include <iostream>
#include <thread>using namespace std;void func() {cout << "hello , this is my thread, thread id is " << this_thread::get_id() << endl;
}
int main() {thread th = thread(func);th.detach();// 如果我們此時不再關系該線程的運行情況的話可以使用detachcout << th.joinable() << endl;cout << "this is main thread and its id is " << this_thread::get_id() << endl;
}

運行結果:

C:\Users\LENOVO\CLionProjects\untitled\cmake-build-debug\untitled.exe
0
this is main thread and its id is 1
hello , this is my thread, thread id is 2Process finished with exit code 0

case2:創建線程2 線程傳參 傳值或者傳引用

傳值

#include <iostream>
#include <thread>using namespace std;void func(string s) {cout << "hello , this is my thread, thread arg is " << s << endl;
}
int main() {thread th = thread(func, "test");th.join();cout << "this is main thread and its id is " << this_thread::get_id() << endl;
}

打印結果如下:

C:\Users\LENOVO\CLionProjects\untitled\cmake-build-debug\untitled.exe
hello , this is my thread, thread arg is test
this is main thread and its id is 1Process finished with exit code 0

傳引用

#include <iostream>
#include <thread>using namespace std;void func(string& s) {cout << (&s) << endl;cout << "hello , this is my thread, thread arg is " << s << endl;
}
int main() {string str = "test";thread th = thread(func, ref(str));cout << (&str) << endl;th.join();cout << "this is main thread and its id is " << this_thread::get_id() << endl;
}

打印結果如下:

C:\Users\LENOVO\CLionProjects\untitled\cmake-build-debug\untitled.exe
0x62fd10
0x62fd10
hello , this is my thread, thread arg is test
this is main thread and its id is 1Process finished with exit code 0

case3:創建線程 線程傳參 functional object作為參數

關于仿函數的定義可以看:仿函數
如果單純地將邏輯函數傳入thread,在函數邏輯比較復雜的時候不太好。
將函數封裝到類的內部,可以賦予一定的封裝性,并且可以在類內部創建例如map的數據結構來記錄函數運行的狀態。
仿函數、不帶參

#include <iostream>
#include <thread>using namespace std;// functional object
struct A {void operator()() {cout << "I'm A" << endl;}
};
void show() {cout << "I'm show" << endl;
}
int main() {show();A a;a();    // 等價于 a.operator()();// 我們把這種object稱為callable的object ,又稱為仿函數thread thread1 = thread(A());thread1.join();return 0;
}

打印結果如下:

C:\Users\LENOVO\CLionProjects\untitled\cmake-build-debug\untitled.exe
I'm show
I'm A
I'm AProcess finished with exit code 0

仿函數、帶參

#include <iostream>
#include <thread>using namespace std;// functional object
struct A {void operator()(int num) {for (int i = 0; i < num; i++) {cout << "I'm A" << i << endl;}}
};int main() {int num = 10;thread thread1 = thread(A(), num);for (int i = 0; i < num; i++) {cout << "I'm main" << i << endl;}thread1.join();return 0;
}

打印結果如下,是亂序的,符合多線程特性
并且 cout 并不是線程安全的,所以可以發現,有亂碼的樣子

C:\Users\LENOVO\CLionProjects\untitled\cmake-build-debug\untitled.exe
I'm mainI'm A00I'm A1
I'm A2
I'm A3
I'm AI'm main41I'm mainI'm A25I'm mainI'm A36I'm AI'm main47I'm main5
I'm mainI'm A86I'm mainI'm A97I'm main8
I'm main9Process finished with exit code 0

lambda函數作為參數

#include <iostream>
#include <thread>using namespace std;int main() {string s = "test";thread f = thread([&s](int a,int b) {cout << s << endl;cout << a + b << endl;}, 2, 3);f.join();return 0;
}

打印結果:

C:\Users\LENOVO\CLionProjects\untitled\cmake-build-debug\untitled.exe
test
5Process finished with exit code 0

case4:觀察多線程程序加速計算

#include <iostream>
#include <thread>using namespace std;// 測量一個函數的運行時間
template <class T>
void measure(T&& func) {using namespace std::chrono;auto start = system_clock::now();// funcfunc();duration<double> diff = system_clock::now() - start;cout << "執行了" << diff.count() << "秒" << endl;
}// 求和函數[start,end)
void sum(long start, long end, long& ans) {long s = 0;for(auto i = start; i < end; i++) {s += i;}ans = s;
}const long S = 100000000;int main() {// 測量一下把工作分攤給兩個線程做的時間measure([](){long ans1, ans2;thread t1 = thread(sum, 0, S >> 1, std::ref(ans1));thread t2 = thread(sum, S >> 1, S, std::ref(ans2));t1.join();t2.join();cout << "ans = " << ans1 + ans2 << endl;});// 測量一下單線程工作時間measure([](){long ans;sum(0, S, ans);cout << "ans = " << ans << endl;});return 0;
}

打印結果:

C:\Users\LENOVO\CLionProjects\untitled\cmake-build-debug\untitled.exe
ans = 887459712
執行了0.13546秒
ans = 887459712
執行了0.240006秒Process finished with exit code 0

當然這里有一個細節:
如果在多線程程序中我們傳入了一個ref引用,在線程程序中我們最好不要直接對這個ref值操作,而是采用一個臨時變量,例如上面的程序中我們就使用了一個臨時變量s,對s進行累加后再把值賦給ans。這樣會提高程序運行效率。

case5:future + get 獲取并發結果

future包裹線程運行結果,使用方法如下:
由于我們線程函數的結果是long,所以首先定義future<long>

#include <iostream>
#include <thread>
#include <future>
#include <vector>using namespace std;// 測量一個函數的運行時間
template <class T>
void measure(T&& func) {using namespace std::chrono;auto start = system_clock::now();// funcfunc();duration<double> diff = system_clock::now() - start;cout << "執行了" << diff.count() << "秒" << endl;
}// 求和函數[start,end)
long sum(long start, long end) {long s = 0;for(auto i = start; i < end; i++) {s += i;}return s;
}const long S = 100000000;int main() {// 測量一下把工作分攤給 threadNums 個線程做的時間measure([](){const long threadNums = 8;vector<future<long>> vec;vec.reserve(threadNums);for (int i = 0; i < threadNums; i++) {vec.push_back(async(sum, (S / threadNums) * i, (S / threadNums) * (i + 1)));}long ans = 0;// get 阻塞式地拿到并發結果for (int i = 0; i < threadNums; i++) {ans += vec[i].get();}cout << "ans = " << ans << endl;});// 測量一下單線程工作時間measure([](){long ans = sum(0, S);cout << "ans = " << ans << endl;});return 0;
}

運行結果如下:

C:\Users\LENOVO\CLionProjects\untitled\cmake-build-debug\untitled.exe
ans = 887459712
執行了0.0521455秒
ans = 887459712
執行了0.250044秒Process finished with exit code 0

case6:互斥鎖

多個線程訪問同一個值并且對其修改,會導致數據競爭。:

#include <iostream>
#include <thread>
#include <future>
#include <vector>using namespace std;
// 測量一個函數的運行時間
template <class T>
void measure(T&& func) {using namespace std::chrono;auto start = system_clock::now();// funcfunc();duration<double> diff = system_clock::now() - start;cout << "執行了" << diff.count() << "秒" << endl;
}std::mutex mtx;
// 求和函數 線程安全的
void sum(long& s) {mtx.lock();for (int i = 0; i < 100000; i++) {s++;}mtx.unlock();
}int main() {// 測量一下把工作分攤給 threadNums 個線程做的時間measure([](){vector<thread> v;long s = 0;for (int i = 0; i < 4; i++) {v.emplace_back(std::thread(sum, std::ref(s)));}for (int i = 0; i < 4; i++) {v[i].join();}cout << "ans " << s << endl;});measure([](){long s = 0;for (int i = 0; i < 4; i++) {sum(s);}cout << "ans " << s << endl;});return 0;
}

測試結果:

C:\Users\LENOVO\CLionProjects\untitled\cmake-build-debug\untitled.exe
ans 400000
執行了0.0141654秒
ans 400000
執行了0.0155926秒Process finished with exit code 0

case7:std::lock_guard 類模板

如果mtx.lock()和mtx.unlock()之間的語句發生了異常,unlock()語句沒有機會執行!
這會導致mtx一直處于鎖著的狀態,其他使用sum函數的線程就會阻塞。
c++庫已經提供了std::lock_guard類模板,構造時自動加鎖,析構時自動解鎖:
將case6的sum函數修改為下面形式即可:

// 求和函數 線程安全的
void sum(long& s) {std:;lock_guard<std::mutex> guard(mtx);// mtx.lock();for (int i = 0; i < 100000; i++) {s++;}// mtx.unlock();
}

如果想自己實現的lock_guard的話也可以:

class mutexLockGuard{
private:std::mutex& mtx;
public:explicit mutexLockGuard(std::mutex& mutex) : mtx(mutex){mtx.lock();}~mutexLockGuard() {mtx.unlock();}
};

筆記參考:
C++多線程快速入門

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/376836.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/376836.shtml
英文地址,請注明出處:http://en.pswp.cn/news/376836.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

android:configChanges屬性總結

原文地址&#xff1a;http://blog.csdn.net/zhaokaiqiang1992/article/details/19921703 android中的組件Activity在manifest.xml文件中可以指定參數android&#xff1a;ConfigChanges&#xff0c;用于捕獲手機狀態的改變。 在Activity中添加了android:configChanges屬性&#…

eclipse 中修改 M2_REPO的值

從eclipse中增加了maven2的插件之后&#xff0c;maven默認的本地庫的路徑是${user}/.m2/repository/下&#xff0c;一般windows用戶的操作系統都安裝在C盤&#xff0c;所以這個目錄 下的jar包比較危險。我嘗試從myeclipse->preferences->java->build path->classpa…

C++多線程快速入門(二)共享數據同步以及數據競爭

目錄std::unique_lock類模板僅調用一次線程局部存儲原子變量往期內容回顧std::unique_lock類模板 互斥鎖保證了線程間的同步&#xff0c;卻將并行操作變成了串行操作&#xff0c;對性能有較大影響&#xff0c;所以我們要盡可能減小鎖的區間粒度。 lock_guard只能保證在析構的時…

DNS安全淺議、域名A記錄(ANAME),MX記錄,CNAME記錄

相關學習資料 http://baike.baidu.com/link?url77B3BYIuVsB3MpK1nOQXI-JbS-AP5MvREzSnnedU7F9_G8l_Kvbkt_O2gKqFw7vm http://www.rfc-editor.org/rfc/rfc1035.txt http://www.rfc-editor.org/rfc/rfc3596.txt http://www.rfc-editor.org/rfc/rfc2782.txt http://www.rfc-edito…

ThinkInJava4讀書筆記之第一章對象入門

那句話怎么說來著&#xff0c;原句記不住了好像是出來混的遲早要還的。話說當初學校剛開Java課程&#xff0c;自己沒有好好學啊&#xff0c;后來直接做了jsp和servlet&#xff0c;然后學了SSH框架和Extjs、jQuery&#xff0c;接著是mybatis&#xff08;ibatis&#xff09;、fre…

C++多線程快速入門(三):生產者消費者模型與條件變量使用

互斥鎖完成 #include <iostream> #include <deque> #include <thread> #include <mutex>std::deque<int> q; std::mutex mtx;static void produce(int val) {while(val--) {std::unique_lock<std::mutex> guard(mtx);q.push_front(val);m…

【blade利刃出鞘】一起進入移動端webapp開發吧

前言 在移動浪潮襲來的時候&#xff0c;小釵有幸進入框架組做webapp框架開發&#xff0c;過程中遇到了移動端的各種坑&#xff0c;也產生了各種激情&#xff0c;就我們公司的發展歷程來說 第一階段&#xff1a;使用傳統方式開發移動站點&#xff0c;少量引入HTML5元素 第二階段…

題目理解。。

有時候一道大水題&#xff0c;因為英文描述可能有點復雜或者其它云云&#xff0c; 就比如那道PRO。。 別先被一道題嚇一跳&#xff0c;&#xff0c;&#xff0c; 英文描述看深入一點總歸會能解決的&#xff0c;盡可能多的考慮情況。大膽嘗試。轉載于:https://www.cnblogs.com/c…

C++多線程快速入門(四)shared_mutex以及讀寫鎖應用

在前面的三講中我們使用的mutex都是普通的std::mutex&#xff0c;這里介紹一下shared_mutex&#xff0c;版本為C17 std::shared_mutex的底層實現時操作系統提供的讀寫鎖&#xff0c;在讀多寫少的情況下&#xff0c;該shared_mutex比mutex更加高效。 它提供了常用的四種方法&am…

Tornado/Python 學習筆記(一)

1.源代碼下載及安裝&#xff1a;http://www.tornadoweb.org/en/stable/ 2.python中xmlrpc庫官方文檔&#xff1a;https://docs.python.org/3/library/xmlrpc.html?highlightxmlrpc 3.xml介紹與學習&#xff1a;http://www.w3school.com.cn/xml/xml_intro.asp XML 被設計為傳輸…

spring-aop-annotation

1。假設你已經配好依賴注入那一塊。此時的bean.xml為 <?xml version"1.0" encoding"UTF-8"?><beans xmlns"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xmlns:cont…

c++實現簡單線程池代碼

目錄完整代碼TaskPool.cppTaskPool.hmain.cpp完整代碼 TaskPool.cpp // // Created by LENOVO on 2021/10/25. //#include "TaskPool.h" #include <functional>std::mutex printMutex;TaskPool::TaskPool() : m_bRunning(false) {}TaskPool::~TaskPool() {re…

Android靜態圖片人臉識別的完整demo(附完整源碼)

Demo功能&#xff1a;利用android自帶的人臉識別進行識別&#xff0c;標記出眼睛和人臉位置。點擊按鍵后進行人臉識別&#xff0c;完畢后顯示到imageview上。 第一部分&#xff1a;布局文件activity_main.xml [html] view plaincopyprint?<RelativeLayout xmlns:android&qu…

圖論:最短路徑搜索--Dijkstra算法(c代碼實現)

最近因為辭職&#xff0c;有不少閑功夫&#xff0c;重溫下數據結構&#xff0c;順便練練手。今天說說最短路徑搜索算法中的Dijkstra原理和實現。 一&#xff1a;簡介 這個算法用于解決圖中單源最短路徑問題。所謂單源節點是指給定源節點&#xff0c;求圖中其它節點到此源節點的…

C++多線程快速入門(五)簡單線程池設計

目錄設計思路主線程運行邏輯task以及taskpool設計詳細流程講解完整代碼打印結果往期回顧設計思路 線程池實際上就是一組線程&#xff0c;當我們需要異步執行一些任務時&#xff0c;經常要通過OS頻繁創建和銷毀線程&#xff0c;不如直接創建一組在程序生命周期內不會退出的線程…

C--函數

函數:具有特定功能的代碼段,分為庫函數,自定義函數. 函數定義: 函數返回值類型 函數名(形式參數列表) { 代碼段; return 返回值; } 注意:每個函數返回值最多只有一個.return是一個函數結束的標志. 形式參數(形參):函數定義時使用的虛擬參數名,用以接收函數調用是傳遞過來的實際…

公式系統 - TradeBlazer公式基礎 - Bar數據

Bar數據 在介紹Bar數據之前&#xff0c;首先&#xff0c;我們需要討論一下TradeBlazer公式的計算方法&#xff0c;針對上面介紹的各種公式類型&#xff0c;包含公式應用&#xff0c;在公式進行計算時&#xff0c;都是建立在基本數據源(Bar數據)之上&#xff0c;我們這里所謂的B…

C++網絡編程快速入門(一):TCP網絡通信基本流程以及基礎函數使用

目錄流程概述服務器端代碼實現客戶端代碼實現函數和結構講解sockaddr_in和sockaddrsocket &#xff1a; 創建一個socket連接bind &#xff1a;綁定地址以及端口號問題流程概述 客戶端與服務器之間的網絡通信基本原理如下所示&#xff0c;復雜一點的架構可能會添加消息中間件。…

php 字符串處理

addcslashes — 為字符串里面的部分字符添加反斜線轉義字符addslashes — 用指定的方式對字符串里面的字符進行轉義bin2hex — 將二進制數據轉換成十六進制表示chop — rtrim() 的別名函數chr — 返回一個字符的ASCII碼chunk_split — 按一定的字符長度將字符串分割成小塊conve…

使用前端框架Foundation 4來幫助簡化響應式設計開發

日期&#xff1a;2013-3-12 來源&#xff1a;GBin1.com Foundation是一套使用廣泛的前端開發套件&#xff0c;可以幫助你快速的網站。最近ZURB發布了一個新版本的Foundation 4前端框架&#xff0c;能夠有效的幫助你快速的開發響應式的網站。 和另外一個套知名的前端框架BootSt…