在C++學(xué)習(xí)過(guò)程中,要想“更上一層樓”的話,多線程編程是必不可少的一步,前面的文章多半是基礎(chǔ)方面的內(nèi)容,這節(jié)的話稍微有點(diǎn)拔高。所以說(shuō),我們?cè)诳催@篇文章的時(shí)候,大家需要更多的思考是為什么這么做?這樣做的好處是什么?以及多線程編程都可以應(yīng)用在哪里?話不多說(shuō),跟著我一起認(rèn)真探討這塊內(nèi)容。
1、多線程 傳統(tǒng)的C++(C++11標(biāo)準(zhǔn)之前)中并沒(méi)有引入線程這個(gè)概念,在C++11出來(lái)之前,如果我們想要在C++中實(shí)現(xiàn)多線程,需要借助操作系統(tǒng)平臺(tái)提供的API,比如Linux的,或者windows下的。 C++11提供了語(yǔ)言層面上的多線程,包含在頭文件中。它解決了跨平臺(tái)的問(wèn)題,提供了管理線程、保護(hù)共享數(shù)據(jù)、線程間同步操作、原子操作等類。C++11 新標(biāo)準(zhǔn)中引入了5個(gè)頭文件來(lái)支持多線程編程,如下圖所示:

1.1、多進(jìn)程與多線程
多進(jìn)程并發(fā)
使用多進(jìn)程并發(fā)是將一個(gè)應(yīng)用程序劃分為多個(gè)獨(dú)立的進(jìn)程(每個(gè)進(jìn)程只有一個(gè)線程),這些獨(dú)立的進(jìn)程間可以互相通信,共同完成任務(wù)。由于操作系統(tǒng)對(duì)進(jìn)程提供了大量的保護(hù)機(jī)制,以避免一個(gè)進(jìn)程修改了另一個(gè)進(jìn)程的數(shù)據(jù),使用多進(jìn)程比使用多線程更容易寫出相對(duì)安全的代碼。但是這也造就了多進(jìn)程并發(fā)的兩個(gè)缺點(diǎn):
在進(jìn)程間的通信,無(wú)論是使用信號(hào)、套接字,還是文件、管道等方式,其使用要么比較復(fù)雜,要么就是速度較慢或者兩者兼而有之。
運(yùn)行多個(gè)線程的開(kāi)銷很大,操作系統(tǒng)要分配很多的資源來(lái)對(duì)這些進(jìn)程進(jìn)行管理。
當(dāng)多個(gè)進(jìn)程并發(fā)完成同一個(gè)任務(wù)時(shí),不可避免的是:操作同一個(gè)數(shù)據(jù)和進(jìn)程間的相互通信,上述的兩個(gè)缺點(diǎn)也就決定了多進(jìn)程的并發(fā)并不是一個(gè)好的選擇。所以就引入了多線程的并發(fā)。
多線程并發(fā)
多線程并發(fā)指的是在同一個(gè)進(jìn)程中執(zhí)行多個(gè)線程。 優(yōu)點(diǎn): 有操作系統(tǒng)相關(guān)知識(shí)的應(yīng)該知道,線程是輕量級(jí)的進(jìn)程,每個(gè)線程可以獨(dú)立的運(yùn)行不同的指令序列,但是線程不獨(dú)立的擁有資源,依賴于創(chuàng)建它的進(jìn)程而存在。也就是說(shuō),同一進(jìn)程中的多個(gè)線程共享相同的地址空間,可以訪問(wèn)進(jìn)程中的大部分?jǐn)?shù)據(jù),指針和引用可以在線程間進(jìn)行傳遞。這樣,同一進(jìn)程內(nèi)的多個(gè)線程能夠很方便的進(jìn)行數(shù)據(jù)共享以及通信,也就比進(jìn)程更適用于并發(fā)操作。 缺點(diǎn): 由于缺少操作系統(tǒng)提供的保護(hù)機(jī)制,在多線程共享數(shù)據(jù)及通信時(shí),就需要程序員做更多的工作以保證對(duì)共享數(shù)據(jù)段的操作是以預(yù)想的操作順序進(jìn)行的,并且要極力的避免死鎖(deadlock)。
1.2、多線程理解
單CPU內(nèi)核的多個(gè)線程。
一個(gè)時(shí)間片運(yùn)行一個(gè)線程的代碼,并不是真正意義的并行計(jì)算。

多個(gè)cpu或者多個(gè)內(nèi)核
可以做到真正的并行計(jì)算。

1.3、創(chuàng)建線程
創(chuàng)建線程很簡(jiǎn)單,只需要把函數(shù)添加到線程當(dāng)中即可。
形式1:
std::thread myThread ( thread_fun); //函數(shù)形式為void thread_fun() myThread.join(); //同一個(gè)函數(shù)可以代碼復(fù)用,創(chuàng)建多個(gè)線程
形式2:
std::thread myThread ( thread_fun(100)); myThread.join(); //函數(shù)形式為void?thread_fun(int?x) //同一個(gè)函數(shù)可以代碼復(fù)用,創(chuàng)建多個(gè)線程
形式3:
std::thread (thread_fun,1).detach(); //直接創(chuàng)建線程,沒(méi)有名字 //函數(shù)形式為void thread_fun(int x)
For Example
使用g++編譯下列代碼的方式:
g++?test.cc?-o?test?-l?pthread
#include
#include
using namespace std;
void thread_1()
{
cout<<"子線程1"<
1.4、join與detach方式
當(dāng)線程啟動(dòng)后,一定要在和線程相關(guān)聯(lián)的thread銷毀前,確定以何種方式等待線程執(zhí)行結(jié)束。比如上例中的join。
detach方式,啟動(dòng)的線程自主在后臺(tái)運(yùn)行,當(dāng)前的代碼繼續(xù)往下執(zhí)行,不等待新線程結(jié)束。
join方式,等待啟動(dòng)的線程完成,才會(huì)繼續(xù)往下執(zhí)行。
可以使用joinable判斷是join模式還是detach模式。
if (myThread.joinable()) foo.join();
(1)join舉例
下面的代碼,join后面的代碼不會(huì)被執(zhí)行,除非子線程結(jié)束。
#include
#include
using namespace std;
void thread_1()
{
while(1)
{
//cout<<"子線程1111"<
}
}
void thread_2(int x)
{
while(1)
{
//cout<<"子線程2222"<
}
}
int main()
{
thread first ( thread_1); // 開(kāi)啟線程,調(diào)用:thread_1()
thread second (thread_2,100); // 開(kāi)啟線程,調(diào)用:thread_2(100)
first.join(); // pauses until first finishes 這個(gè)操作完了之后才能destroyed
second.join(); // pauses until second finishes//join完了之后,才能往下執(zhí)行。
while(1)
{
std::cout << "主線程
";
?? }
return 0;
}
(2)detach舉例
下列代碼中,主線程不會(huì)等待子線程結(jié)束。如果主線程運(yùn)行結(jié)束,程序則結(jié)束。
#include
#include
using namespace std;
void thread_1()
{
while(1)
{
?? cout<<"子線程1111"<
}
}
void thread_2(int x)
{
while(1)
{
cout<<"子線程2222"<
}
}
int main()
{
thread first ( thread_1); // 開(kāi)啟線程,調(diào)用:thread_1()
thread second (thread_2,100); // 開(kāi)啟線程,調(diào)用:thread_2(100)
first.detach();
second.detach();
for(int i = 0; i < 10; i++)
{
std::cout << "主線程
";
}
return 0;
}
1.5、this_thread
this_thread是一個(gè)類,它有4個(gè)功能函數(shù),具體如下:
函數(shù)
使用
說(shuō)明
get_id
std::get_id()
獲取線程id
yield
std::yield()
放棄線程執(zhí)行,回到就緒狀態(tài)
sleep_for
std::seconds(1));
暫停1秒
sleep_until
如下
一分鐘后執(zhí)行嗎,如下
using std::system_clock;
std::time_t tt = system_clock::to_time_t(system_clock::now());
struct std::tm * ptm = std::localtime(&tt);
cout << "Waiting for the next minute to begin...
";
++ptm->tm_min; //加一分鐘
ptm->tm_sec = 0; //秒數(shù)設(shè)置為0//暫停執(zhí)行,到下一整分執(zhí)行
this_thread::from_time_t(mktime(ptm)));
2、mutex mutex頭文件主要聲明了與互斥量(mutex)相關(guān)的類。mutex提供了4種互斥類型,如下表所示。
類型
說(shuō)明
std::mutex
最基本的 Mutex 類。
std::recursive_mutex
遞歸 Mutex 類。
std::time_mutex
定時(shí) Mutex 類。
std::recursive_timed_mutex
定時(shí)遞歸 Mutex 類。
std::mutex 是C++11 中最基本的互斥量,std::mutex 對(duì)象提供了獨(dú)占所有權(quán)的特性——即不支持遞歸地對(duì) std::mutex 對(duì)象上鎖,而 std::recursive_lock 則可以遞歸地對(duì)互斥量對(duì)象上鎖。
2.1、lock與unlock
mutex常用操作:
lock():資源上鎖
unlock():解鎖資源
trylock():查看是否上鎖,它有下列3種類情況:
(1)未上鎖返回false,并鎖住; (2)其他線程已經(jīng)上鎖,返回true; (3)同一個(gè)線程已經(jīng)對(duì)它上鎖,將會(huì)產(chǎn)生死鎖。
死鎖:是指兩個(gè)或兩個(gè)以上的進(jìn)程在執(zhí)行過(guò)程中,由于競(jìng)爭(zhēng)資源或者由于彼此通信而造成的一種阻塞的現(xiàn)象,若無(wú)外力作用,它們都將無(wú)法推進(jìn)下去。此時(shí)稱系統(tǒng)處于死鎖狀態(tài)或系統(tǒng)產(chǎn)生了死鎖,這些永遠(yuǎn)在互相等待的進(jìn)程稱為死鎖進(jìn)程。
下面結(jié)合實(shí)例對(duì)lock和unlock進(jìn)行說(shuō)明。 同一個(gè)mutex變量上鎖之后,一個(gè)時(shí)間段內(nèi),只允許一個(gè)線程訪問(wèn)它。例如:
#include// std::cout
#include// std::thread
#include// std::mutex
std::mutex mtx; // mutex for critical section
void print_block (int n, char c)
{
// critical section (exclusive access to std::cout signaled by locking mtx):
mtx.lock();
for (int i=0; i
{
std::cout << c;
????}
std::cout << '
';
mtx.unlock();
}
int main ()
{
std::thread th1 (print_block,50,'');//線程1:打印*
std::thread th2 (print_block,50,'$');//線程2:打印$
th1.join();
th2.join();
return 0;
}
輸出:
**************************************************
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
? 如果是不同mutex變量,因?yàn)椴簧婕暗酵毁Y源的競(jìng)爭(zhēng),所以以下代碼運(yùn)行可 能會(huì)出現(xiàn)交替打印的情況,或者另一個(gè)線程可以修改共同的全局變量!
#include // std::cout
#include // std::thread
#include // std::mutex
std::mutex mtx_1; // mutex for critical section
std::mutex mtx_2; // mutex for critical section
int test_num = 1;
void print_block_1 (int n, char c)
{
// critical section (exclusive access to std::cout signaled by locking mtx):
mtx_1.lock();
for (int i=0; i
{
//std::cout << c;
test_num = 1;
std::cout<
2.2、lock_guard 創(chuàng)建lock_guard對(duì)象時(shí),它將嘗試獲取提供給它的互斥鎖的所有權(quán)。當(dāng)控制流離開(kāi)lock_guard對(duì)象的作用域時(shí),lock_guard析構(gòu)并釋放互斥量。 lock_guard的特點(diǎn):
創(chuàng)建即加鎖,作用域結(jié)束自動(dòng)析構(gòu)并解鎖,無(wú)需手工解鎖
不能中途解鎖,必須等作用域結(jié)束才解鎖
不能復(fù)制
代碼舉例
#include
#include
#include
int g_i = 0;
std::mutex g_i_mutex; // protects g_i,用來(lái)保護(hù)g_i
void safe_increment()
{
const std::lock_guard lock(g_i_mutex);
++g_i;
std::cout << std::get_id() << ": " << g_i << '
';// g_i_mutex自動(dòng)解鎖}int main(){
std::cout << "main id: " <
?說(shuō)明:
該程序的功能為,每經(jīng)過(guò)一個(gè)線程,g_i 加1。
因?yàn)樯婕暗焦餐Y源g_i ,所以需要一個(gè)共同mutex:g_i_mutex。
main線程的id為1,所以下次的線程id依次加1。
2.3、unique_lock
簡(jiǎn)單地講,unique_lock 是 lock_guard 的升級(jí)加強(qiáng)版,它具有 lock_guard 的所有功能,同時(shí)又具有其他很多方法,使用起來(lái)更加靈活方便,能夠應(yīng)對(duì)更復(fù)雜的鎖定需要。 unique_lock的特點(diǎn):
創(chuàng)建時(shí)可以不鎖定(通過(guò)指定第二個(gè)參數(shù)為std::defer_lock),而在需要時(shí)再鎖定
可以隨時(shí)加鎖解鎖
作用域規(guī)則同 lock_grard,析構(gòu)時(shí)自動(dòng)釋放鎖
不可復(fù)制,可移動(dòng)
條件變量需要該類型的鎖作為參數(shù)(此時(shí)必須使用unique_lock)
所有 lock_guard 能夠做到的事情,都可以使用 unique_lock 做到,反之則不然。那么何時(shí)使lock_guard呢?很簡(jiǎn)單,需要使用鎖的時(shí)候,首先考慮使用 lock_guard,因?yàn)閘ock_guard是最簡(jiǎn)單的鎖。 下面是代碼舉例:
#include
#include
#include
struct Box {
explicit Box(int num) : num_things{num} {}
int num_things;
std::mutex m;
};
void transfer(Box &from, Box &to, int num)
{
// defer_lock表示暫時(shí)unlock,默認(rèn)自動(dòng)加鎖
std::unique_lock lock1(from.m, std::defer_lock);
std::unique_lock lock2(to.m, std::defer_lock);//兩個(gè)同時(shí)加鎖
std::lock(lock1, lock2);//或者使用lock1.lock()
from.num_things -= num;
to.num_things += num;//作用域結(jié)束自動(dòng)解鎖,也可以使用lock1.unlock()手動(dòng)解鎖
}
int main()
{
Box acc1(100);
Box acc2(50);
std::thread t1(transfer, std::ref(acc1), std::ref(acc2), 10);
std::thread t2(transfer, std::ref(acc2), std::ref(acc1), 5);
t1.join();
t2.join();
std::cout << "acc1 num_things: " << acc1.num_things << std::endl;
std::cout << "acc2 num_things: " << acc2.num_things << std::endl;
}
說(shuō)明:
該函數(shù)的作用是,從一個(gè)結(jié)構(gòu)體中的變量減去一個(gè)num,加載到另一個(gè)結(jié)構(gòu)體的變量中去。
std::mutex m;在結(jié)構(gòu)體中,mutex不是共享的。但是只需要一把鎖也能鎖住,因?yàn)橐脗鬟f后,同一把鎖傳給了兩個(gè)函數(shù)。
cout需要在join后面進(jìn)行,要不然cout的結(jié)果不一定是最終算出來(lái)的結(jié)果。
std::ref 用于包裝按引用傳遞的值。
std::cref 用于包裝按const引用傳遞的值。
3、condition_variable condition_variable頭文件有兩個(gè)variable類,一個(gè)是condition_variable,另一個(gè)是condition_variable_any。condition_variable必須結(jié)合unique_lock使用。condition_variable_any可以使用任何的鎖。下面以condition_variable為例進(jìn)行介紹。 condition_variable條件變量可以阻塞(wait、wait_for、wait_until)調(diào)用的線程直到使用(notify_one或notify_all)通知恢復(fù)為止。condition_variable是一個(gè)類,這個(gè)類既有構(gòu)造函數(shù)也有析構(gòu)函數(shù),使用時(shí)需要構(gòu)造對(duì)應(yīng)的condition_variable對(duì)象,調(diào)用對(duì)象相應(yīng)的函數(shù)來(lái)實(shí)現(xiàn)上面的功能。
?
類型
說(shuō)明
condition_variable
構(gòu)建對(duì)象
析構(gòu)
刪除
wait
Wait until notified
wait_for
Wait for timeout or until notified
wait_until
Wait until notified or time point
notify_one
解鎖一個(gè)線程,如果有多個(gè),則未知哪個(gè)線程執(zhí)行
notify_all
解鎖所有線程
cv_status
這是一個(gè)類,表示variable 的狀態(tài),如下所示
enum class cv_status { no_timeout, timeout };
3.1、wait 當(dāng)前線程調(diào)用 wait() 后將被阻塞(此時(shí)當(dāng)前線程應(yīng)該獲得了鎖(mutex),不妨設(shè)獲得鎖 lck),直到另外某個(gè)線程調(diào)用 notify_* 喚醒了當(dāng)前線程。 在線程被阻塞時(shí),該函數(shù)會(huì)自動(dòng)調(diào)用 lck.unlock() 釋放鎖,使得其他被阻塞在鎖競(jìng)爭(zhēng)上的線程得以繼續(xù)執(zhí)行。另外,一旦當(dāng)前線程獲得通知(notified,通常是另外某個(gè)線程調(diào)用 notify_* 喚醒了當(dāng)前線程),wait()函數(shù)也是自動(dòng)調(diào)用 lck.lock(),使得lck的狀態(tài)和 wait 函數(shù)被調(diào)用時(shí)相同。 代碼示例:
#include // std::cout
#include // std::thread, std::yield
#include // std::mutex, std::unique_lock
#include // std::condition_variable
std::mutex mtx;
std::condition_variable cv;
int cargo = 0;
bool shipment_available()
{
return cargo!=0;
}
void consume (int n)
{
for (int i=0; i
{
std::unique_lock lck(mtx);//自動(dòng)上鎖
//第二個(gè)參數(shù)為false才阻塞(wait),阻塞完即unlock,給其它線程資源
cv.wait(lck,shipment_available);// consume:
std::cout << cargo << '
';
cargo=0;
}
}
int main ()
{
std::thread consumer_thread (consume,10);
for (int i=0; i<10; ++i)
{
//每次cargo每次為0才運(yùn)行。
????while?(shipment_available())??std::yield();
std::unique_lock lck(mtx);
cargo = i+1;
cv.notify_one();
}
????consumer_thread.join();
????return?0;
}
說(shuō)明:
主線程中的while,每次在cargo=0才運(yùn)行。
每次cargo被置為0,會(huì)通知子線程unblock(非阻塞),也就是子線程可以繼續(xù)往下執(zhí)行。
子線程中cargo被置為0后,wait又一次啟動(dòng)等待。也就是說(shuō)shipment_available為false,則等待。
3.2、wait_for
與std::wait() 類似,不過(guò) wait_for可以指定一個(gè)時(shí)間段,在當(dāng)前線程收到通知或者指定的時(shí)間 rel_time 超時(shí)之前,該線程都會(huì)處于阻塞狀態(tài)。而一旦超時(shí)或者收到了其他線程的通知,wait_for返回,剩下的處理步驟和 wait()類似。
template
cv_status wait_for (unique_lock& lck,
??????????????????????const?chrono::duration&?rel_time);
另外,wait_for 的重載版本的最后一個(gè)參數(shù)pred表示 wait_for的預(yù)測(cè)條件,只有當(dāng) pred條件為false時(shí)調(diào)用 wait()才會(huì)阻塞當(dāng)前線程,并且在收到其他線程的通知后只有當(dāng) pred為 true時(shí)才會(huì)被解除阻塞。
template
bool wait_for (unique_lock& lck,
?????????const?chrono::duration&?rel_time,?Predicate?pred);
代碼示例:
#include// std::cout
#include// std::thread
#include// std::seconds
#include// std::mutex, std::unique_lock
#include// std::condition_variable, std::cv_status
std::condition_variable cv;
int value;
void read_value()
{
std::cin >> value;
cv.notify_one();
}
int main ()
{
std::cout << "Please, enter an integer (I'll be printing dots):
";
std::thread th (read_value);
std::mutex mtx;
std::unique_lock lck(mtx);
while (cv.wait_for(lck,std::seconds(1))==std::timeout)
{
std::cout << '.' << std::endl;
}
std::cout << "You entered: " << value << '
';
th.join();
return 0;
}
通知或者超時(shí)都會(huì)解鎖,所以主線程會(huì)一直打印。
示例中只要過(guò)去一秒,就會(huì)不斷的打印。
4、線程池
4.1、概念
在一個(gè)程序中,如果我們需要多次使用線程,這就意味著,需要多次的創(chuàng)建并銷毀線程。而創(chuàng)建并銷毀線程的過(guò)程勢(shì)必會(huì)消耗內(nèi)存,線程過(guò)多會(huì)帶來(lái)調(diào)動(dòng)的開(kāi)銷,進(jìn)而影響緩存局部性和整體性能。 線程的創(chuàng)建并銷毀有以下一些缺點(diǎn):
創(chuàng)建太多線程,將會(huì)浪費(fèi)一定的資源,有些線程未被充分使用。
銷毀太多線程,將導(dǎo)致之后浪費(fèi)時(shí)間再次創(chuàng)建它們。
創(chuàng)建線程太慢,將會(huì)導(dǎo)致長(zhǎng)時(shí)間的等待,性能變差。
銷毀線程太慢,導(dǎo)致其它線程資源饑餓。
線程池維護(hù)著多個(gè)線程,這避免了在處理短時(shí)間任務(wù)時(shí),創(chuàng)建與銷毀線程的代價(jià)。
4.2、線程池的實(shí)現(xiàn)
因?yàn)槌绦蜻呥\(yùn)行邊創(chuàng)建線程是比較耗時(shí)的,所以我們通過(guò)池化的思想:在程序開(kāi)始運(yùn)行前創(chuàng)建多個(gè)線程,這樣,程序在運(yùn)行時(shí),只需要從線程池中拿來(lái)用就可以了.大大提高了程序運(yùn)行效率. 一般線程池都會(huì)有以下幾個(gè)部分構(gòu)成:
線程池管理器(ThreadPoolManager):用于創(chuàng)建并管理線程池,也就是線程池類
工作線程(WorkThread): 線程池中線程
任務(wù)隊(duì)列task: 用于存放沒(méi)有處理的任務(wù)。提供一種緩沖機(jī)制。
append:用于添加任務(wù)的接口
線程池實(shí)現(xiàn)代碼:
#ifndef _THREADPOOL_H
#define _THREADPOOL_H
#include
#include
#include
#include
#include
#include
#include//unique_ptr
#include
const int MAX_THREADS = 1000; //最大線程數(shù)目
template
class threadPool
{
public:
threadPool(int number = 1);//默認(rèn)開(kāi)一個(gè)線程
~threadPool();
std::queuetasks_queue; //任務(wù)隊(duì)列
bool append(T *request);//往請(qǐng)求隊(duì)列<task_queue>中添加任務(wù)
private:
//工作線程需要運(yùn)行的函數(shù),不斷的從任務(wù)隊(duì)列中取出并執(zhí)行
static void *worker(void arg);
void run();
private:
std::vector work_threads; //工作線程
std::mutex queue_mutex;
std::condition_variable condition; //必須與unique_lock配合使用
bool stop;
};//end class//構(gòu)造函數(shù),創(chuàng)建線程
template
threadPool::threadPool(int number) : stop(false)
{
if?(number?<=?0?||?number?>?MAX_THREADS)
throw?std::exception();
for?(int?i?=?0;?i?
inline threadPool::~threadPool()
{
????std::unique_lock?lock(queue_mutex);
????stop?=?true;
????
condition.notify_all();
for (auto &ww : work_threads)
ww.join();//可以在析構(gòu)函數(shù)中join
}
//添加任務(wù)
template
bool threadPool::append(T *request)
{
????//操作工作隊(duì)列時(shí)一定要加鎖,因?yàn)樗凰芯€程共享
queue_mutex.lock();//同一個(gè)類的鎖
tasks_queue.push(request);
queue_mutex.unlock();
????condition.notify_one();??//線程池添加進(jìn)去了任務(wù),自然要通知等待的線程
return true;
}//單個(gè)線程
template
void threadPool::worker(void *arg)
{
threadPool pool = (threadPool *)arg;
pool->run();//線程運(yùn)行
return pool;
}
template
void threadPool::run()
{
while (!stop)
{
std::unique_lock lk(this->queue_mutex);
/* unique_lock() 出作用域會(huì)自動(dòng)解鎖 /
this->condition.wait(lk, [this]
{
return !this->tasks_queue.empty();
});//如果任務(wù)為空,則wait,就停下來(lái)等待喚醒//需要有任務(wù),才啟動(dòng)該線程,不然就休眠
if (this->tasks_queue.empty())//任務(wù)為空,雙重保障
{
assert(0&&"斷了");//實(shí)際上不會(huì)運(yùn)行到這一步,因?yàn)槿蝿?wù)為空,wait就休眠了。
continue;
}else{
T *request = tasks_queue.front();
tasks_queue.pop();
if (request)//來(lái)任務(wù)了,開(kāi)始執(zhí)行
request->process();
}
}
}
#endif
說(shuō)明:
構(gòu)造函數(shù)創(chuàng)建所需要的線程數(shù)
一個(gè)線程對(duì)應(yīng)一個(gè)任務(wù),任務(wù)隨時(shí)可能完成,線程則可能休眠,所以任務(wù)用隊(duì)列queue實(shí)現(xiàn)(線程數(shù)量有限),線程用采用wait機(jī)制。
任務(wù)在不斷的添加,有可能大于線程數(shù),處于隊(duì)首的任務(wù)先執(zhí)行。
只有添加任務(wù)(append)后,才開(kāi)啟線程condition.notify_one()。
wait表示,任務(wù)為空時(shí),則線程休眠,等待新任務(wù)的加入。
添加任務(wù)時(shí)需要添加鎖,因?yàn)楣蚕碣Y源。
測(cè)試代碼:
#include "mythread.h"
#include
#include
using namespace std;
class Task
{
public:
void process()
{
//cout << "run........." << endl;//測(cè)試任務(wù)數(shù)量
long i=1000000;
while(i!=0)
{
int j = sqrt(i);
????????????i--;
}
}
};
int?main(void){
threadPoolpool(6);//6個(gè)線程,vector
std::string str;
while (1)
{
Task *tt = new Task();//使用智能指針
pool.append(tt);//不停的添加任務(wù),任務(wù)是隊(duì)列queue,因?yàn)橹挥泄潭ǖ木€程數(shù)
??????cout<<"添加的任務(wù)數(shù)量:"<
編輯:黃飛
?
電子發(fā)燒友App
















評(píng)論