一、前言
1. 多線程的含義
多線程(multithreading),是指在軟件或者硬件上實(shí)現(xiàn)多個(gè)線程并發(fā)執(zhí)行的技術(shù)。具有多核CPU的支持的計(jì)算機(jī)能夠真正在同一時(shí)間執(zhí)行多個(gè)程序片段,進(jìn)而提升程序的處理性能。在一個(gè)程序中,這些獨(dú)立運(yùn)行的程序片段被稱為“線程”(Thread),利用其編程的概念就叫作“多線程處理”。
2. 進(jìn)程與線程的區(qū)別
進(jìn)程是指一個(gè)程序的運(yùn)行實(shí)例,而線程是指進(jìn)程中獨(dú)立的執(zhí)行流程。一個(gè)進(jìn)程可以有多個(gè)線程,多個(gè)線程之間可以并發(fā)執(zhí)行。
- 一個(gè)程序有且只有一個(gè)進(jìn)程,但可以擁有至少一個(gè)的線程。
- 不同進(jìn)程擁有不同的地址空間,互不相關(guān),而不同線程共同擁有相同進(jìn)程的地址空間。
二、創(chuàng)建線程
1. thread
C++支持多線程編程,主要使用的是線程庫(kù)<thread>
。
示例1: 創(chuàng)建線程使用std::thread
類
#include <iostream>
#include <thread> //必須包含<thread>頭文件
void threadFunctionA()
{
std::cout << "Run New thread: 1" << std::endl;
}
void threadFunctionB(int n)
{
std::cout << "Run New thread: "<< n << std::endl;
}
int main()
{
std::cout << "Run Main Thread" << std::endl;
std::thread newThread1(threadFunctionA);
std::thread newThread2(threadFunctionB,2);
newThread1.join();
newThread2.join();
return 0;
}
//result
Run Main Thread
Run New thread: 1
Run New thread: 2
上述示例中,我們創(chuàng)建了兩個(gè)線程newThread1和newThread2,使用函數(shù)threadFunctionA()
和threadFunctionB()
作為線程的執(zhí)行函數(shù),并使用join()
函數(shù)等待線程執(zhí)行完成。
示例2: 執(zhí)行函數(shù)有引用參數(shù)
#include <iostream>
#include <thread> //必須包含<thread>頭文件
void threadFunc(int &arg1, int arg2)
{
arg1 = arg2;
std::cout << "arg1 = " << arg1 << std::endl;
}
int main()
{
std::cout << "Run Main Thread!" << std::endl;
int a = 1;
int b = 5;
std::thread newTh(threadFunc, a, b); //此處會(huì)報(bào)錯(cuò)
newTh.join();
return 0;
}
注意: 若編譯上述代碼,編譯器會(huì)報(bào)如下錯(cuò)誤:
錯(cuò)誤 C2672 “std::invoke”: 未找到匹配的重載函數(shù)
錯(cuò)誤 C2893 未能使函數(shù)模板“unknown-type std::invoke(_Callable &&,_Types &&...) noexcept(<expr>)”專用化
這是因?yàn)?strong>thread在傳遞參數(shù)時(shí),是以右值傳遞的,如果要傳遞一個(gè)左值可以使用std::ref
和std::cref
-
std::ref
可以包裝按引用傳遞的值為右值。 -
std::cref
可以包裝按const
引用傳遞的值為右值。
因此,示例2代碼可修改為:
#include <iostream>
#include <thread> //必須包含<thread>頭文件
void threadFunc(int &arg1, int arg2)
{
arg1 = arg2;
std::cout << "New Thread arg1 = " << arg1 << std::endl;
}
int main()
{
std::cout << "Run Main Thread!" << std::endl;
int a = 1, b = 5;
std::thread newTh(threadFunc, std::ref(a), b); //使用ref
newTh.join();
return 0;
}
//result
Run Main Thread!
arg1 = 5
2. join() 和 detach()
在C++中,創(chuàng)建了一個(gè)線程時(shí),它通常被稱為一個(gè)可聯(lián)接(joinable)
的線程,可以通過(guò)調(diào)用join()
函數(shù)或detach()
函數(shù)來(lái)管理線程的執(zhí)行。
方法 | 說(shuō)明 | |
---|---|---|
1 | join() | 等待一個(gè)線程完成,如果該線程還未執(zhí)行完畢,則當(dāng)前線程(一般是主線程)將被阻塞,直到該線程執(zhí)行完成,主線程才會(huì)繼續(xù)執(zhí)行。 |
2 | detach() | 將當(dāng)前線程與創(chuàng)建的線程分離,使它們分別運(yùn)行,當(dāng)分離的線程執(zhí)行完畢后,系統(tǒng)會(huì)自動(dòng)回收其資源。如果一個(gè)線程被分離了,就不能再使用join() 函數(shù)了,因?yàn)榫€程已經(jīng)無(wú)法被聯(lián)接了。 |
3 | joinable() | 判斷線程是否可以執(zhí)行join() 函數(shù),返回true/false
|
示例3:
#include <iostream>
#include <thread>
#include <windows.h>
void foo()
{
std::cout << "Run New thread!\n";
Sleep(2000); //需要頭文件<windows.h>
}
int main()
{
std::thread t(foo);
if (t.joinable())
{
t.join(); // 等待線程t執(zhí)行完畢
// t.detach(); // 分離線程t與主線程
}
std::cout << "Run Main thread!\n";
return 0;
}
在上述的示例中,創(chuàng)建了一個(gè)可聯(lián)接的線程t
,使用t.join()
主線程將被阻塞,直到t
線程執(zhí)行完畢。如果使用t.detach()
將t
線程分離,那么它們將同時(shí)執(zhí)行,主線程將不會(huì)阻塞。
注意:
- 線程是在thread對(duì)象被定義的時(shí)候開始執(zhí)行的,而不是在調(diào)用
join()
函數(shù)時(shí)才執(zhí)行的,調(diào)用join()
函數(shù)只是阻塞等待線程結(jié)束并回收資源。 - 分離的線程(執(zhí)行過(guò)
detach()
的線程)會(huì)在調(diào)用它的線程結(jié)束或自己結(jié)束時(shí)自動(dòng)釋放資源。 - 線程會(huì)在函數(shù)運(yùn)行完畢后自動(dòng)釋放,不推薦利用其他方法強(qiáng)制結(jié)束線程,可能會(huì)因資源未釋放而導(dǎo)致內(nèi)存泄漏。
- 若沒(méi)有執(zhí)行
join()
或detach()
的線程在程序結(jié)束時(shí)會(huì)引發(fā)異常。
3. this_thread
在C++中,this_thread
類提供了一些關(guān)于當(dāng)前線程的功能函數(shù)。具體如下:
使用 | 說(shuō)明 | |
---|---|---|
1 | std::this_thread::sleep_for() | 當(dāng)前線程休眠指定的時(shí)間 |
2 | std::this_thread::sleep_until() | 當(dāng)前線程休眠直到指定時(shí)間點(diǎn) |
3 | std::this_thread::yield() | 當(dāng)前線程讓出CPU,允許其他線程運(yùn)行 |
4 | std::this_thread::get_id() | 獲取當(dāng)前線程的ID |
此外,this_thread
還包含重載運(yùn)算符==
和!=
,用于比較兩個(gè)線程是否相等。
示例4:
#include <iostream>
#include <thread>
#include <chrono>
void my_thread()
{
std::cout << "Thread " << std::this_thread::get_id() << " start!" << std::endl;
for (int i = 1; i <= 5; i++)
{
std::cout << "Thread " << std::this_thread::get_id() << " running: " << i << std::endl;
std::this_thread::yield(); // 讓出當(dāng)前線程的時(shí)間片
std::this_thread::sleep_for(std::chrono::milliseconds(200)); // 線程休眠200毫秒
}
std::cout << "Thread " << std::this_thread::get_id() << " end!" << std::endl;
}
int main()
{
std::cout << "Main thread id: " << std::this_thread::get_id() << std::endl;
std::thread t1(my_thread);
std::thread t2(my_thread);
t1.join();
t2.join();
return 0;
}
//result 程序輸出的結(jié)果可能如下:
Main thread id: 43108
Thread 39272 start!
Thread 33480 start!
Thread 33480 running: 1
Thread 39272 running: 1
Thread 33480 running: 2
Thread 39272 running: 2
Thread 33480 running: 3
Thread 39272 running: 3
Thread 33480 running: 4
Thread 39272 running: 4
Thread 39272 running: 5
Thread 33480 running: 5
Thread 39272 ends
Thread 33480 ends
三、std::mutex
在多線程編程中,需要注意以下問(wèn)題:
- 線程之間的共享數(shù)據(jù)訪問(wèn)需要進(jìn)行同步,以防止數(shù)據(jù)競(jìng)爭(zhēng)和其他問(wèn)題。可以使用互斥量、條件變量等機(jī)制進(jìn)行同步。
- 可能會(huì)發(fā)生死鎖問(wèn)題,即多個(gè)線程互相等待對(duì)方釋放鎖,導(dǎo)致程序無(wú)法繼續(xù)執(zhí)行。
- 可能會(huì)發(fā)生競(jìng)態(tài)條件問(wèn)題,即多個(gè)線程執(zhí)行的順序?qū)е陆Y(jié)果的不確定性。
1. lock() 與 unlock()
std::mutex
是 C++11 中最基本的互斥量,一個(gè)線程將mutex鎖住時(shí),其它的線程就不能操作mutex,直到這個(gè)線程將mutex解鎖。
方法 | 說(shuō)明 | |
---|---|---|
1 | lock() | 將mutex上鎖。如果mutex已經(jīng)被其它線程上鎖,那么會(huì)阻塞,直到解鎖;如果mutex已經(jīng)被同一個(gè)線程鎖住,那么會(huì)產(chǎn)生死鎖。 |
2 | unlock() |
將mutex解鎖,釋放其所有權(quán)。如果有線程因?yàn)檎{(diào)用lock() 不能上鎖而被阻塞,則調(diào)用此函數(shù)會(huì)將mutex的主動(dòng)權(quán)隨機(jī)交給其中一個(gè)線程;如果mutex不是被此線程上鎖,那么會(huì)引發(fā)未定義的異常。 |
3 | try_lock() | 嘗試將mutex上鎖。如果mutex未被上鎖,則將其上鎖并返回true;如果mutex已被鎖則返回false。 |
示例: 使用互斥量
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx;
int num = 0;
void thread_function(int &n)
{
for (int i = 0; i < 100; ++i)
{
mtx.lock();
n++;
mtx.unlock();
}
}
int main()
{
std::thread myThread[500];
for (std::thread &a : myThread)
{
a = std::thread(thread_function, std::ref(num));
a.join();
}
std::cout << "num = " << num << std::endl;
std::cout << "Main thread exits!" << std::endl;
return 0;
}
//result
num = 50000
Main thread exits!
注意: 在使用互斥量時(shí),需要注意以下問(wèn)題:
- 加鎖和解鎖的順序必須相同。
- 不能在未獲得鎖的情況下對(duì)共享數(shù)據(jù)進(jìn)行操作。
- 由于使用了
std::mutex
來(lái)控制對(duì)共享資源的訪問(wèn),因此可能會(huì)對(duì)程序的性能造成影響,如果需要優(yōu)化程序性能,可以考慮使用無(wú)鎖編程等技術(shù)。
2. lock_guard
std::lock_guard
是C++標(biāo)準(zhǔn)庫(kù)中的一個(gè)模板類,用于實(shí)現(xiàn)資源的自動(dòng)加鎖和解鎖。它是基于RAII(資源獲取即初始化)的設(shè)計(jì)理念,能夠確保在作用域結(jié)束時(shí)自動(dòng)釋放鎖資源,避免了手動(dòng)管理鎖的復(fù)雜性和可能出現(xiàn)的錯(cuò)誤。
std::lock_guard
的主要特點(diǎn)如下:
-
自動(dòng)加鎖: 在創(chuàng)建
std::lock_guard
對(duì)象時(shí),會(huì)立即對(duì)指定的互斥量進(jìn)行加鎖操作。這樣可以確保在進(jìn)入作用域后,互斥量已經(jīng)被鎖定,避免了并發(fā)訪問(wèn)資源的競(jìng)爭(zhēng)條件。 -
自動(dòng)解鎖:
std::lock_guard
對(duì)象在作用域結(jié)束時(shí),會(huì)自動(dòng)釋放互斥量。無(wú)論作用域是通過(guò)正常的流程結(jié)束、異常拋出還是使用return
語(yǔ)句提前返回,std::lock_guard
都能保證互斥量被正確解鎖,避免了資源泄漏和死鎖的風(fēng)險(xiǎn)。 -
適用于局部鎖定: 由于
std::lock_guard
是通過(guò)棧上的對(duì)象實(shí)現(xiàn)的,因此適用于在局部范圍內(nèi)鎖定互斥量。當(dāng)超出std::lock_guard
對(duì)象的作用域時(shí),互斥量會(huì)自動(dòng)解鎖,釋放控制權(quán)。
使用std::lock_guard
的一般步驟如下:
- 創(chuàng)建一個(gè)
std::lock_guard
對(duì)象,傳入要加鎖的互斥量作為參數(shù)。 - 執(zhí)行需要加鎖保護(hù)的代碼塊。
-
std::lock_guard
對(duì)象的作用域結(jié)束時(shí),自動(dòng)調(diào)用析構(gòu)函數(shù)解鎖互斥量。
示例:
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx; // 互斥量
void thread_function()
{
std::lock_guard<std::mutex> lock(mtx); // 加鎖互斥量
std::cout << "Thread running" << std::endl;
// 執(zhí)行需要加鎖保護(hù)的代碼
} // lock_guard對(duì)象的析構(gòu)函數(shù)自動(dòng)解鎖互斥量
int main()
{
std::thread t1(thread_function);
t1.join();
std::cout << "Main thread exits!" << std::endl;
return 0;
}
在上述示例中,std::lock_guard
對(duì)象lock
會(huì)在thread_function
中加鎖互斥量,保護(hù)了輸出語(yǔ)句的執(zhí)行。當(dāng)thread_function
結(jié)束時(shí),lock_guard
對(duì)象的析構(gòu)函數(shù)會(huì)自動(dòng)解鎖互斥量。這樣可以確?;コ饬吭诤线m的時(shí)候被鎖定和解鎖,避免了多線程間的競(jìng)爭(zhēng)問(wèn)題。
總而言之,std::lock_guard
提供了一種簡(jiǎn)單而安全的方式來(lái)管理互斥量的鎖定和解鎖,使多線程編程更加方便和可靠。
3. unique_lock
std::unique_lock
是C++標(biāo)準(zhǔn)庫(kù)中的一個(gè)模板類,用于實(shí)現(xiàn)更加靈活的互斥量的加鎖和解鎖操作。它提供了比std::lock_guard
更多的功能和靈活性。
std::unique_lock
的主要特點(diǎn)如下:
-
自動(dòng)加鎖和解鎖: 與
std::lock_guard
類似,std::unique_lock
在創(chuàng)建對(duì)象時(shí)立即對(duì)指定的互斥量進(jìn)行加鎖操作,確保互斥量被鎖定。在對(duì)象的生命周期結(jié)束時(shí),會(huì)自動(dòng)解鎖互斥量。這種自動(dòng)加鎖和解鎖的機(jī)制避免了手動(dòng)管理鎖的復(fù)雜性和可能出現(xiàn)的錯(cuò)誤。 -
支持靈活的加鎖和解鎖: 相對(duì)于
std::lock_guard
的自動(dòng)加鎖和解鎖,std::unique_lock
提供了更靈活的方式。它可以在需要的時(shí)候手動(dòng)加鎖和解鎖互斥量,允許在不同的代碼塊中對(duì)互斥量進(jìn)行多次加鎖和解鎖操作。 -
支持延遲加鎖和條件變量:
std::unique_lock
還支持延遲加鎖的功能,可以在不立即加鎖的情況下創(chuàng)建對(duì)象,稍后根據(jù)需要進(jìn)行加鎖操作。此外,它還可以與條件變量(std::condition_variable
)一起使用,實(shí)現(xiàn)更復(fù)雜的線程同步和等待機(jī)制。
使用std::unique_lock
的一般步驟如下:
- 創(chuàng)建一個(gè)
std::unique_lock
對(duì)象,傳入要加鎖的互斥量作為參數(shù)。 - 執(zhí)行需要加鎖保護(hù)的代碼塊。
- 可選地手動(dòng)調(diào)用
lock
函數(shù)對(duì)互斥量進(jìn)行加鎖,或者在需要時(shí)調(diào)用unlock
函數(shù)手動(dòng)解鎖互斥量。
示例:
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx; // 互斥量
void thread_function()
{
std::unique_lock<std::mutex> lock(mtx); // 加鎖互斥量
std::cout << "Thread running" << std::endl;
// 執(zhí)行需要加鎖保護(hù)的代碼
lock.unlock(); // 手動(dòng)解鎖互斥量
// 執(zhí)行不需要加鎖保護(hù)的代碼
lock.lock(); // 再次加鎖互斥量
// 執(zhí)行需要加鎖保護(hù)的代碼
}
// unique_lock對(duì)象的析構(gòu)函數(shù)自動(dòng)解鎖互斥量
int main()
{
std::thread t1(thread_function);
t1.join();
std::cout << "Main thread exits!" << std::endl;
return 0;
}
在上述示例中,std::unique_lock
對(duì)象lock
會(huì)在創(chuàng)建時(shí)自動(dòng)加鎖互斥量,析構(gòu)時(shí)自動(dòng)解鎖互斥量。我們可以通過(guò)調(diào)用lock
和unlock
函數(shù)手動(dòng)控制加鎖和解鎖的時(shí)機(jī),以實(shí)現(xiàn)更靈活的操作。
總而言之,std::unique_lock
提供了更靈活和功能豐富的互斥量的加鎖和解鎖機(jī)制,使多線程編程更加便捷和安全。它在處理復(fù)雜的同步需求、延遲加鎖以及與條件變量的結(jié)合等方面非常有用。
四、condition_variable
std::condition_variable
是C++標(biāo)準(zhǔn)庫(kù)中的一個(gè)類,用于在多線程編程中實(shí)現(xiàn)線程間的條件變量和線程同步。它提供了等待和通知的機(jī)制,使得線程可以等待某個(gè)條件成立時(shí)被喚醒,或者在滿足某個(gè)條件時(shí)通知其他等待的線程。其提供了以下幾個(gè)函數(shù)用于等待和通知線程:
方法 | 說(shuō)明 | |
---|---|---|
1 | wait | 使當(dāng)前線程進(jìn)入等待狀態(tài),直到被其他線程通過(guò)notify_one() 或notify_all() 函數(shù)喚醒。該函數(shù)需要一個(gè)互斥鎖作為參數(shù),調(diào)用時(shí)會(huì)自動(dòng)釋放互斥鎖,并在被喚醒后重新獲取互斥鎖。 |
2 | wait_for |
wait_for() : 使當(dāng)前線程進(jìn)入等待狀態(tài),最多等待一定的時(shí)間,直到被其他線程通過(guò)notify_one() 或notify_all() 函數(shù)喚醒,或者等待超時(shí)。該函數(shù)需要一個(gè)互斥鎖和一個(gè)時(shí)間段作為參數(shù),返回時(shí)有兩種情況:等待超時(shí)返回std::cv_status::timeout ,被喚醒返回std::cv_status::no_timeout 。 |
3 | wait_until |
wait_until() : 使當(dāng)前線程進(jìn)入等待狀態(tài),直到被其他線程通過(guò)notify_one() 或notify_all() 函數(shù)喚醒,或者等待時(shí)間達(dá)到指定的絕對(duì)時(shí)間點(diǎn)。該函數(shù)需要一個(gè)互斥鎖和一個(gè)絕對(duì)時(shí)間點(diǎn)作為參數(shù),返回時(shí)有兩種情況:時(shí)間到達(dá)返回std::cv_status::timeout ,被喚醒返回std::cv_status::no_timeout 。 |
4 | notify_one |
notify_one() : 喚醒一個(gè)等待中的線程,如果有多個(gè)線程在等待,則選擇其中一個(gè)線程喚醒。 |
5 | notify_all |
notify_all() : 喚醒所有等待中的線程,使它們從等待狀態(tài)返回。 |
std::condition_variable
的主要特點(diǎn)如下:
-
等待和通知機(jī)制:
std::condition_variable
允許線程進(jìn)入等待狀態(tài),直到某個(gè)條件滿足時(shí)才被喚醒。線程可以調(diào)用wait
函數(shù)進(jìn)入等待狀態(tài),并指定一個(gè)互斥量作為參數(shù),以確保線程在等待期間互斥量被鎖定。當(dāng)其他線程滿足條件并調(diào)用notify_one
或notify_all
函數(shù)時(shí),等待的線程將被喚醒并繼續(xù)執(zhí)行。 -
與互斥量配合使用:
std::condition_variable
需要與互斥量(std::mutex
或std::unique_lock<std::mutex>
)配合使用,以確保線程之間的互斥性。在等待之前,線程必須先鎖定互斥量,以避免競(jìng)爭(zhēng)條件。當(dāng)條件滿足時(shí),通知其他等待的線程之前,必須再次鎖定互斥量。 -
支持超時(shí)等待:
std::condition_variable
提供了帶有超時(shí)參數(shù)的等待函數(shù)wait_for
和wait_until
,允許線程在等待一段時(shí)間后自動(dòng)被喚醒。這對(duì)于處理超時(shí)情況或限時(shí)等待非常有用。
使用std::condition_variable
的一般步驟如下:
- 創(chuàng)建一個(gè)
std::condition_variable
對(duì)象。 - 創(chuàng)建一個(gè)互斥量對(duì)象(
std::mutex
或std::unique_lock<std::mutex>
)。 - 在等待線程中,使用
std::unique_lock
鎖定互斥量,并調(diào)用wait
函數(shù)進(jìn)入等待狀態(tài)。 - 在喚醒線程中,使用
std::unique_lock
鎖定互斥量,并調(diào)用notify_one
或notify_all
函數(shù)通知等待的線程。 - 等待線程被喚醒后,繼續(xù)執(zhí)行相應(yīng)的操作。
示例:
#include <iostream>
#include <thread>
#include <condition_variable>
std::mutex mtx; // 互斥量
std::condition_variable cv; // 條件變量
bool isReady = false; // 條件
void thread_function()
{
std::unique_lock<std::mutex> lock(mtx);
while (!isReady)
{
cv.wait(lock); // 等待條件滿足
}
std::cout << "Thread is notified" << std::endl;
}
int main()
{
std::thread t(thread_function);
// 模擬一段耗時(shí)操作
std::this_thread::sleep_for(std::chrono::seconds(2));
{
std::lock_guard<std::mutex> lock(mtx);
isReady = true; // 設(shè)置條件為true
}
cv.notify_one(); // 通知等待的線程
t.join();
return 0;
}
上述示例中,創(chuàng)建了一個(gè)線程,該線程在等待狀態(tài)下通過(guò)cv.wait(lock)
等待條件滿足。主線程經(jīng)過(guò)一段時(shí)間后將條件設(shè)置為true
,然后通過(guò)cv.notify_one()
通知等待的線程。等待的線程被喚醒后輸出一條消息。
五、std::atomic
std::mutex
可以很好地解決多線程資源爭(zhēng)搶的問(wèn)題,但它每次循環(huán)都要加鎖、解鎖,這樣固然會(huì)浪費(fèi)很多的時(shí)間。
在 C++ 中,std::atomic
是用來(lái)提供原子操作的類,atomic,本意為原子,原子操作是最小的且不可并行化的操作。這就意味著即使是多線程,也要像同步進(jìn)行一樣同步操作原子對(duì)象,從而省去了互斥量上鎖、解鎖的時(shí)間消耗。
使用 std::atomic
可以保證數(shù)據(jù)在操作期間不被其他線程修改,這樣就避免了數(shù)據(jù)競(jìng)爭(zhēng),使得程序在多線程并發(fā)訪問(wèn)時(shí)仍然能夠正確執(zhí)行。
示例:
#include <iostream>
#include <thread>
#include <mutex>
#include <atomic> //必須包含
std::atomic_int num = 0;
void thread_function(std::atomic_int &n) //修改類型
{
for (int i = 0; i < 100; ++i)
{
n++;
}
}
int main()
{
std::thread myThread[500];
for (std::thread &a : myThread)
{
a = std::thread(thread_function, std::ref(num));
a.join();
}
std::cout << "num = " << num << std::endl;
std::cout << "Main thread exits!" << std::endl;
return 0;
}
//result
num = 50000
Main thread exits!
說(shuō)明:std::atomic_int
是std::atomic<int>
的別名。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-625797.html
如果這篇文章對(duì)你有所幫助,渴望獲得你的一個(gè)點(diǎn)贊!
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-625797.html
到了這里,關(guān)于【C++】多線程(thread)使用詳解的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!