您好,登錄后才能下訂單哦!
這篇文章給大家分享的是有關(guān)c++11線程為什么需要互斥量的內(nèi)容。小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過(guò)來(lái)看看吧。
在多任務(wù)操作系統(tǒng)中,同時(shí)運(yùn)行的多個(gè)任務(wù)可能都需要使用同一種資源。這個(gè)過(guò)程有點(diǎn)類(lèi)似于,公司部門(mén)里,我在使用著打印機(jī)打印東西的同時(shí)(還沒(méi)有打印完),別人剛好也在此刻使用打印機(jī)打印東西,如果不做任何處理的話,打印出來(lái)的東西肯定是錯(cuò)亂的。
#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string> #include <chrono> #include <thread> // 打印機(jī) void printer(const char *str) { while(*str != '\0') { std::cout << *str; str++; std::this_thread::sleep_for(std::chrono::milliseconds(1000)); } std::cout << std::endl; } // 線程一 void func1() { const char *str = "hello"; printer(str); } // 線程二 void func2() { const char *str = "world"; printer(str); } void mytest() { std::thread t1(func1); std::thread t2(func2); t1.join(); t2.join(); return; } int main() { mytest(); system("pause"); return 0; }
互斥量的基本接口很相似,一般用法是通過(guò)lock()方法來(lái)阻塞線程,直到獲得互斥量的所有權(quán)為止。在線程獲得互斥量并完成任務(wù)之后,就必須使用unlock()來(lái)解除對(duì)互斥量的占用,lock()和unlock()必須成對(duì)出現(xiàn)。try_lock()嘗試鎖定互斥量,如果成功則返回true, 如果失敗則返回false,它是非阻塞的。
#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string> #include <chrono> #include <thread> #include <mutex> std::mutex g_lock; //全局互斥鎖對(duì)象,#include <mutex> // 打印機(jī) void printer(const char *str) { g_lock.lock(); //上鎖 while(*str != '\0') { std::cout << *str; str++; std::this_thread::sleep_for(std::chrono::milliseconds(1000)); } std::cout << std::endl; g_lock.unlock(); // 解鎖 } // 線程一 void func1() { const char *str = "hello"; printer(str); } // 線程二 void func2() { const char *str = "world"; printer(str); } void mytest() { std::thread t1(func1); std::thread t2(func2); t1.join(); t2.join(); return; } int main() { mytest(); system("pause"); return 0; }
使用std::lock_guard可以簡(jiǎn)化lock/unlock的寫(xiě)法,同時(shí)也更安全,因?yàn)閘ock_guard在構(gòu)造時(shí)會(huì)自動(dòng)鎖定互斥量,而在退出作用域后進(jìn)行析構(gòu)時(shí)就會(huì)自動(dòng)解鎖,從而避免忘了unlock操作。
#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string> #include <chrono> #include <thread> #include <mutex> std::mutex g_lock; //全局互斥鎖對(duì)象,#include <mutex> // 打印機(jī) void printer(const char *str) { std::lock_guard<std::mutex> locker(g_lock); // lock_guard 上鎖 while(*str != '\0') { std::cout << *str; str++; std::this_thread::sleep_for(std::chrono::milliseconds(1000)); } std::cout << std::endl; // 即將推出作用域 lock_guard 會(huì)自動(dòng)解鎖 } // 線程一 void func1() { const char *str = "hello"; printer(str); } // 線程二 void func2() { const char *str = "world"; printer(str); } void mytest() { std::thread t1(func1); std::thread t2(func2); t1.join(); t2.join(); return; } int main() { mytest(); system("pause"); return 0; }
所謂的原子操作,取的就是“原子是最小的、不可分割的最小個(gè)體”的意義,它表示在多個(gè)線程訪問(wèn)同一個(gè)全局資源的時(shí)候,能夠確保所有其他的線程都不在同一時(shí)間內(nèi)訪問(wèn)相同的資源。也就是他確保了在同一時(shí)刻只有唯一的線程對(duì)這個(gè)資源進(jìn)行訪問(wèn)。這有點(diǎn)類(lèi)似互斥對(duì)象對(duì)共享資源的訪問(wèn)的保護(hù),但是原子操作更加接近底層,因而效率更高。
#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string> #include <chrono> #include <thread> //全局的結(jié)果數(shù)據(jù) long total = 0; //點(diǎn)擊函數(shù) void func() { for(int i = 0; i < 1000000; ++i) { // 對(duì)全局?jǐn)?shù)據(jù)進(jìn)行無(wú)鎖訪問(wèn) total += 1; } } void mytest() { clock_t start = clock(); // 計(jì)時(shí)開(kāi)始 //線程 std::thread t1(func); std::thread t2(func); t1.join(); t2.join(); clock_t end = clock(); // 計(jì)時(shí)結(jié)束 std::cout << "total = " << total << std::endl; std::cout << "time = " << end-start << " ms" << std::endl; return; } int main() { mytest(); system("pause"); return 0; }
由于線程間對(duì)數(shù)據(jù)的競(jìng)爭(zhēng)而導(dǎo)致每次運(yùn)行的結(jié)果都不一樣。因此,為了防止數(shù)據(jù)競(jìng)爭(zhēng)問(wèn)題,我們需要對(duì)total進(jìn)行原子操作。
通過(guò)互斥鎖進(jìn)行原子操作:
#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string> #include <chrono> #include <thread> #include <mutex> std::mutex g_lock; //全局的結(jié)果數(shù)據(jù) long total = 0; //點(diǎn)擊函數(shù) void func() { for(int i = 0; i < 1000000; ++i) { g_lock.lock(); // 加鎖 total += 1; g_lock.unlock(); // 加鎖 } } void mytest() { clock_t start = clock(); // 計(jì)時(shí)開(kāi)始 //線程 std::thread t1(func); std::thread t2(func); t1.join(); t2.join(); clock_t end = clock(); // 計(jì)時(shí)結(jié)束 std::cout << "total = " << total << std::endl; std::cout << "time = " << end-start << " ms" << std::endl; return; } int main() { mytest(); system("pause"); return 0; }
每次運(yùn)行的結(jié)果都一樣,只是耗時(shí)長(zhǎng)點(diǎn)。
在新標(biāo)準(zhǔn)C++11,引入了原子操作的概念。
如果我們?cè)诙鄠€(gè)線程中對(duì)這些類(lèi)型的共享資源進(jìn)行操作,編譯器將保證這些操作都是原子性的,也就是說(shuō),確保任意時(shí)刻只有一個(gè)線程對(duì)這個(gè)資源進(jìn)行訪問(wèn),編譯器將保證多個(gè)線程訪問(wèn)這個(gè)共享資源的正確性。從而避免了鎖的使用,提高了效率。
#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string> #include <chrono> #include <thread> #include <atomic> //原子數(shù)據(jù)類(lèi)型 std::atomic<long> total(0); //需要頭文件 #include <atomic> //點(diǎn)擊函數(shù) void func() { for(int i = 0; i < 1000000; ++i) { // total += 1; } } void mytest() { clock_t start = clock(); // 計(jì)時(shí)開(kāi)始 //線程 std::thread t1(func); std::thread t2(func); t1.join(); t2.join(); clock_t end = clock(); // 計(jì)時(shí)結(jié)束 std::cout << "total = " << total << std::endl; std::cout << "time = " << end-start << " ms" << std::endl; return; } int main() { mytest(); system("pause"); return 0; }
原子操作的實(shí)現(xiàn)跟普通數(shù)據(jù)類(lèi)型類(lèi)似,但是它能夠在保證結(jié)果正確的前提下,提供比mutex等鎖機(jī)制更好的性能。
感謝各位的閱讀!關(guān)于“c++11線程為什么需要互斥量”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。