中文字幕日韩精品一区二区免费_精品一区二区三区国产精品无卡在_国精品无码专区一区二区三区_国产αv三级中文在线

C++多線程筆記-創(chuàng)新互聯(lián)

線程的基本使用 thread

創(chuàng)建線程的函數(shù),頭文件thread。參數(shù)可以是函數(shù)名、仿函數(shù)、lambda表達式、類等等。

創(chuàng)新互聯(lián)是一家專業(yè)提供江漢企業(yè)網(wǎng)站建設(shè),專注與做網(wǎng)站、網(wǎng)站設(shè)計、H5高端網(wǎng)站建設(shè)、小程序制作等業(yè)務(wù)。10年已為江漢眾多企業(yè)、政府機構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)網(wǎng)站建設(shè)公司優(yōu)惠進行中。join

等待子線程執(zhí)行完畢

子線程和子進程的死亡是有些區(qū)別的。主進程執(zhí)行完成后,如果子進程沒有執(zhí)行完會被系統(tǒng)init托管;主線程執(zhí)行完后,如果子線程還沒有執(zhí)行完,子線程會被強制結(jié)束。這就有了join函數(shù),等待子線程執(zhí)行完后在繼續(xù)執(zhí)行。

detach

守護線程,detach的作用是使主線程結(jié)束后,子線程不會強制結(jié)束

joinable

判斷線程是否執(zhí)行了join或者detach這兩個函數(shù),沒有調(diào)用返回true

線程傳遞參數(shù)注意事項 線程中函數(shù)參數(shù)
  • 如果線程中的函數(shù)參數(shù)是引用類型,傳遞的其實也是拷貝。如果不給參數(shù)增加std::ref的話,除了指針都是值傳遞
  • 如果使用的detach后,使用指針傳遞要注意參數(shù)內(nèi)存釋放的時機,如果主線程結(jié)束后,子線程的參數(shù)內(nèi)存肯定是會被釋放的
  • 如果想改變主線程中的參數(shù),在傳遞參數(shù)的時候可以加上std::ref,此時要注意內(nèi)存問題
  • 如果傳遞int這種簡單類型,推薦使用值傳遞,不要用引用
  • 如果傳遞類對象,參數(shù)需要用const &去接,這樣可以少執(zhí)行一次拷貝構(gòu)造
  • 拒接使用隱士轉(zhuǎn)換當參數(shù),隱式轉(zhuǎn)換實在子線程中進行轉(zhuǎn)換的,可能出現(xiàn)內(nèi)存問題,要使用顯示轉(zhuǎn)換
mutex互斥量用法、死鎖 互斥量的用法

? 包含#include 頭文件

  • lock(),unlock()

    步驟:1.lock(),2.操作共享數(shù)據(jù),3.unlock()。
    lock()和unlock()要成對使用
    2.2 lock_guard類模板

  • lock_guard sbguard(myMutex);
    取代lock()和unlock()
    lock_guard構(gòu)造函數(shù)執(zhí)行了mutex::lock();在作用域結(jié)束時,調(diào)用析構(gòu)函數(shù),執(zhí)行mutex::unlock()

死鎖

? 兩個線程都已經(jīng)鎖了部分資源,還在互相請求對方已經(jīng)上鎖的資源,都不釋放資源,就會造成死鎖

解決死鎖
  • std::lock()函數(shù)模板

    • std::lock(mutex1,mutex2……); 一次鎖定多個互斥量(一般這種情況很少),用于處理多個互斥量。
    • 如果互斥量中一個沒鎖住,它就等著,等所有互斥量都鎖住,才能繼續(xù)執(zhí)行。如果有一個沒鎖住,就會
    • 已經(jīng)鎖住的釋放掉(要么互斥量都鎖住,要么都沒鎖住,防止死鎖)
  • std::lock_guard的std::adopt_lock參數(shù)

    • std::lock_guardstd::mutex my_guard(my_mutex,std::adopt_lock);
    • 加入adopt_lock后,在調(diào)用lock_guard的構(gòu)造函數(shù)時,不再進行l(wèi)ock();
    • adopt_guard為結(jié)構(gòu)體對象,起一個標記作用,表示這個互斥量已經(jīng)lock(),不需要在lock()。
unique_lock(類模板) unique_lock取代lock_guard
unique_lock比lock_guard靈活很多(多出來很多用法),效率差一點。
 unique_lockmyUniLock(myMutex);
unique_lock的第二個參數(shù)
  • std::adopt_lock:
    • 表示這個互斥量已經(jīng)被lock(),即不需要在構(gòu)造函數(shù)中l(wèi)ock這個互斥量了。
    • 前提:必須提前l(fā)ock
    • lock_guard中也可以用這個參數(shù)
  • std::try_to_lock
    • 嘗試用mutex的lock()去鎖定這個mutex,但如果沒有鎖定成功,會立即返回,不會阻塞在那里;
    • 使用try_to_lock的原因是防止其他的線程鎖定mutex太長時間,導致本線程一直阻塞在lock這個地方前提:不能提前l(fā)ock();
    • owns_lock()方法判斷是否拿到鎖,如拿到返回true
  • std::defer_lock:
    • 如果沒有第二個參數(shù)就對mutex進行加鎖,加上defer_lock是始化了一個沒有加鎖的mutex
    • 不給它加鎖的目的是以后可以調(diào)用unique_lock的一些方法
    • 前提:不能提前l(fā)ock
unique_lock的成員函數(shù)(前三個與std::defer_lock聯(lián)合使用)
  • lock()
    • 加鎖,不用自己調(diào)用unlock()
  • unlock()
    • 因為一些非共享代碼要處理,可以暫時先unlock(),用其他線程把它們處理了,處理完后再lock()
  • try_lock()
    • 如果拿不到鎖,返回false,否則返回true
  • release()
    • 解除綁定
條件鎖 condition_variable

std::condition_variable實際上是一個類,是一個和條件相關(guān)的類,說白了就是等待一個條件達成。

列舉一些他的成員函數(shù)

wait()

線程等待,并且會放下鎖

wait(線程名,條件函數(shù)(可以省略默認true))

調(diào)用該方法后會進入堵塞狀態(tài),需要等待比額的線程調(diào)用notify_one()或者notify_all()來喚醒,喚醒后會嘗試繼續(xù)拿起釋放掉的鎖

notify_one()

喚醒一個執(zhí)行過wait還在等待的線程,無法指定喚醒哪一個,是隨機喚醒1個

notify_all()

喚醒所有執(zhí)行了wait還在等待的線程

future、saync

多線程如果函數(shù)有返回值,可以使用這兩個去接收返回值

std::future result1 = std::async(mythread);

執(zhí)行futrue的get方法,就可以獲得mythread的返回值,如果函數(shù)還沒有運行完,那么會進入堵塞,一直到有返回值再繼續(xù)

futrue的wait就是等待返回值,是一個堵塞的方法。

saync的參數(shù)

saync有兩個參數(shù),第一個參數(shù)是如何創(chuàng)建線程,第二個參數(shù)是線程函數(shù)名字

如果不指定,就是兩個隨機

std::launch::deferred

該參數(shù)線程不會直接創(chuàng)建線程,而且等待執(zhí)行。

當用戶調(diào)用get方法的時候,才會執(zhí)行線程。

注意:他不會創(chuàng)建線程,也是在主線程中執(zhí)行的方法

std::launch::async

該參數(shù)就是直接創(chuàng)建線程直接。是直接執(zhí)行的

std::packaged_task

類模板,它的模板參數(shù)是各種可調(diào)用對象,通過packaged_task把各種可調(diào)用對象包裝起來,方便將來作為線程入口函數(shù)來調(diào)用。

std::packaged_taskmypt(mythread);

std::thread t1(std::ref(mypt), 1);

并不會直接調(diào)用線程,還是需要使用thread去創(chuàng)建顯示,他的作用只是打包

可以通過 get_future(); 獲取返回值

std::promise類模板

我們能夠在某個線程中給它賦值,然后我們可以在其他線程中,把這個值取出來

std::promise myprom;
std::thread t1(mythread, std::ref(myprom), 180);
t1.join(); //在這里線程已經(jīng)執(zhí)行完了
std::future fu1 = myprom.get_future(); //promise和future綁定,用于獲取線程返回值

把他當成一個參數(shù)傳入,在線程中用setValue來改變他的值,在主線程獲取參數(shù)

std::async和std::thread()區(qū)別:

std::thread()如果系統(tǒng)資源緊張可能出現(xiàn)創(chuàng)建線程失敗的情況,如果創(chuàng)建線程失敗那么程序就可能崩潰,而且不容易拿到函數(shù)返回值(不是拿不到)
std::async()創(chuàng)建異步任務(wù)??赡軇?chuàng)建線程也可能不創(chuàng)建線程,并且容易拿到線程入口函數(shù)的返回值;

由于系統(tǒng)資源限制:
①如果用std::thread創(chuàng)建的線程太多,則可能創(chuàng)建失敗,系統(tǒng)報告異常,崩潰。

②如果用std::async,一般就不會報異常,因為如果系統(tǒng)資源緊張,無法創(chuàng)建新線程的時候,async不加額外參數(shù)的調(diào)用方式就不會創(chuàng)建新線程。而是在后續(xù)調(diào)用get()請求結(jié)果時執(zhí)行在這個調(diào)用get()的線程上。

如果你強制async一定要創(chuàng)建新線程就要使用 std::launch::async 標記。承受的代價是,系統(tǒng)資源緊張時可能崩潰。

③根據(jù)經(jīng)驗,一個程序中線程數(shù)量 不宜超過100~200 。

std::atomic

原子類,執(zhí)行不會被中斷

只能使用++ – 或者+=類似的運算符才可以保證原子性

Windows臨界區(qū)

臨界區(qū)跟上鎖類似,有進入臨界區(qū),離開臨界區(qū),作用和和鎖是一樣的。

創(chuàng)建臨界區(qū)

CRITICAL_SECTION my_winsec;

初始化臨界區(qū)

InitializeCriticalSection(&my_winsec)

進入臨界區(qū)

EnterCriticalSection(&my_winsec);

是可以重復進入的,mutex是無法重復lock的

離開臨界區(qū)

LeaveCriticalSection(&my_winsec);

手寫自動自動離開的臨界區(qū)
class CWinLock {public:
    CWinLock(CRITICAL_SECTION *pCritmp)
    {my_winsec =pCritmp;
        EnterCriticalSection(my_winsec);
    }
    ~CWinLock()
    {LeaveCriticalSection(my_winsec)
    };
private:
    CRITICAL_SECTION *my_winsec;
};
遞歸鎖 獨占互斥量 std::recursive_mutex

std::mutex 獨占式互斥量

std::recursive_mutex:允許在同一個線程中同一個互斥量多次被 lock() ,(但是遞歸加鎖的次數(shù)是有限制的,太多可能會報異常),效率要比mutex低。

如果你真的用了 recursive_mutex 要考慮代碼是否有優(yōu)化空間,如果能調(diào)用一次 lock()就不要調(diào)用多次。

帶超時的互斥量 std::timed_mutex 和 std::recursive_timed_mutexstd::timed_mutex:是待超時的獨占互斥量
  • try_lock_for():

  • 等待一段時間,如果拿到了鎖,或者超時了未拿到鎖,就繼續(xù)執(zhí)行(有選擇執(zhí)行)

  • try_lock_until():

    • 參數(shù)是一個未來的時間點,在這個未來的時間沒到的時間內(nèi),如果拿到了鎖頭,流程就走下來,如果時間到了沒拿到鎖,流程也可以走下來。

    兩者的區(qū)別就是一個參數(shù)是時間段,一個參數(shù)是時間點

std::recursive_timed_mutex:是待超時的遞歸獨占互斥量自旋鎖

自旋鎖(spinlock):是指當一個線程在獲取鎖的時候,如果鎖已經(jīng)被其它線程獲取,那么該線程將循環(huán)等待,然后不斷的判斷鎖是否能夠被成功獲取,直到獲取到鎖才會退出循環(huán)。

獲取鎖的線程一直處于活躍狀態(tài),但是并沒有執(zhí)行任何有效的任務(wù),使用這種鎖會造成busy-waiting。即不斷的消耗cpu

它是為實現(xiàn)保護共享資源而提出一種鎖機制。其實,自旋鎖與互斥鎖比較類似,它們都是為了解決對某項資源的互斥使用。無論是互斥鎖,還是自旋鎖,在任何時刻,最多只能有一個保持者,也就說,在任何時刻最多只能有一個執(zhí)行單元獲得鎖。但是兩者在調(diào)度機制上略有不同。對于互斥鎖,如果資源已經(jīng)被占用,資源申請者只能進入睡眠狀態(tài)。但是自旋鎖不會引起調(diào)用者睡眠,如果自旋鎖已經(jīng)被別的執(zhí)行單元保持,調(diào)用者就一直循環(huán)在那里看是否該自旋鎖的保持者已經(jīng)釋放了鎖,”自旋”一詞就是因此而得名。

class CAS
{private:
	std::atomicflag;
public:
	CAS():flag(false) {}
	~CAS() {}
	CAS(const CAS& s) = delete;
	CAS& operator=(const CAS&) = delete;
	void lock()
	{bool expect = false;
		while (!flag.compare_exchange_strong(expect, true))
		{	expect = false;
		}
	}
	void unlock()
	{flag.store(false);
	}
};
compare_exchange_strong

當前值與期望值(expect)相等時,修改當前值為設(shè)定值(desired,第二個參數(shù)),返回true
當前值與期望值(expect)不等時,將期望值(expect)修改為當前值,返回false

總結(jié)

自旋鎖:線程獲取鎖的時候,如果鎖被其他線程持有,則當前線程將循環(huán)等待,直到獲取到鎖。

自旋鎖等待期間,線程的狀態(tài)不會改變,線程一直是用戶態(tài)并且是活動的(active)。

自旋鎖如果持有鎖的時間太長,則會導致其它等待獲取鎖的線程耗盡CPU。

自旋鎖本身無法保證公平性,同時也無法保證可重入性。

基于自旋鎖,可以實現(xiàn)具備公平性和可重入性質(zhì)的鎖

讀寫鎖

相比互斥鎖,讀寫鎖允許更高的并行性,互斥量要么鎖住狀態(tài)要么不加鎖,而且一次只有一個線程可以加鎖。
讀寫鎖可以有三種狀態(tài):

  • 讀模式加鎖狀態(tài);
  • 寫模式加鎖狀態(tài);
  • 不加鎖狀態(tài);
排他性鎖定 lock

鎖定互斥。若另一線程已鎖定互斥,則lock的調(diào)用線程將阻塞執(zhí)行,直至獲得鎖。
若已以任何模式(共享或排他性)占有 mutex 的線程調(diào)用 lock ,則行為未定義。也就是說,已經(jīng)獲得讀模式鎖或者寫模式鎖的線程再次調(diào)用lock的話,行為是未定義的。
注意:通常不直接使用std::shared_mutex::lock(),而是通過unique_lock或者lock_guard進行管理。

unlock

解鎖互斥。
互斥必須為當前執(zhí)行線程所鎖定,否則行為未定義。如果當前線程不擁有該互斥還去調(diào)用unlock,那么就不知道去unlock誰,行為是未定義的。
注意:通常不直接調(diào)用 unlock() 而是用 std::unique_lock 與 std::lock_guard 管理排他性鎖定。

共享鎖定 std::shared_mutex::lock_shared

相比mutex,shared_mutex還擁有l(wèi)ock_shared函數(shù)。
該函數(shù)獲得互斥的共享所有權(quán)。若另一線程以排他性所有權(quán)保有互斥,則lock_shared的調(diào)用者將阻塞執(zhí)行,直到能取得共享所有權(quán)。
若已以任何模式(排他性或共享)占有 mutex 的線程調(diào)用 lock_shared ,則行為未定義。即:當以讀模式或者寫模式擁有鎖的線程再次調(diào)用lock_shared時,行為是未定義的,可能產(chǎn)生死鎖。
若多于實現(xiàn)定義大數(shù)量的共享所有者已以共享模式鎖定互斥,則 lock_shared 阻塞執(zhí)行,直至共享所有者的數(shù)量減少。所有者的大數(shù)量保證至少為 10000。
注意:通常不直接調(diào)用 lock_shared() 而是用 std::shared_lock 管理共享鎖定。
shared_lock與unique_lock的使用方法類似、

std::shared_mutex::unlock_shared

將互斥從調(diào)用方線程的共享所有權(quán)釋放。
當前執(zhí)行線程必須以共享模式鎖定互斥,否則行為未定義。
通常不直接調(diào)用 unlock_shared() 而是用 std::shared_lock 管理共享鎖定。

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧

名稱欄目:C++多線程筆記-創(chuàng)新互聯(lián)
文章轉(zhuǎn)載:http://www.rwnh.cn/article22/cciecc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供App開發(fā)、自適應(yīng)網(wǎng)站、動態(tài)網(wǎng)站響應(yīng)式網(wǎng)站、靜態(tài)網(wǎng)站網(wǎng)站營銷

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站托管運營
新平| 四平市| 阳高县| 修水县| 阜城县| 随州市| 石门县| 景德镇市| 大城县| 荔浦县| 连平县| 孙吴县| 灵宝市| 文水县| 景德镇市| 泊头市| 浦江县| 河北区| 昭平县| 蒙山县| 陆河县| 毕节市| 涡阳县| 博白县| 都昌县| 恩平市| 乐业县| 阳江市| 通辽市| 梅河口市| 岚皋县| 修水县| 元阳县| 屏南县| 西吉县| 灵台县| 新津县| 无棣县| 兴隆县| 浮山县| 新绛县|