C++封裝POSIX 線程庫(四)使用封裝的線程
本文主要介紹如何使用 C++封裝POSIX 線程庫(一)互斥鎖、C++封裝POSIX 線程庫(二)條件變量的封裝和C++封裝POSIX 線程庫(三)線程的封裝三文中介紹的POSIX Pthread的基本元件(互斥鎖,條件變量和線程)C++封裝的使用。
設計一個場景讓我們用到這三個元件:一共啟動三個線程,其中兩個線程負責互斥地對`count“變量進行increment增量操作,另外一個線程則對count變量進行監視,使用條件變量等待其到達某個值時才喚醒修改count的值。
1. 繼承與重寫run方法
我們封裝了Thread類,并設定成員函數run()為純虛函數,是以我們使用類繼承,并重寫run方法:
//main.cpp
class IncCount : public Thread//增加計數線程
{
private:
int id_;
public:
IncCount(int id):id_(id){}
void run()
{
for(int i=;i < ;i ++)
{
{
MutexLockGuard lock(mutex);
count++;
if (count == )
{
cond.notify();//通知
}
//列印資訊友善調試
std::cout<<"thread : "<<id_<<" count : "<< count << std::endl;
}//臨界區
sleep();//注:sleep不是同步原語,這裡隻是為了友善調試
}
}
};
class WatchCount: public Thread//監視線程
{
private:
int id_;
public:
WatchCount(int id):id_(id){}
void run()
{
MutexLockGuard lock(mutex);//加鎖
while(count < )//這裡用while防止虛假喚醒
{
cond.wait();
}
assert(count>=);
count+=;
std::cout<<"thread : "<<id_<<" count : "<< count << std::endl;
}
};
2. shared_ptr和多态
用C++封裝Pthread元件讓我們很容易想到多态這個特性,當然我們完全可以這樣寫:
//main.cpp
int main()
{
WatchCount t1();
IncCount t2();
IncCount t3();
t1.start();
t2.start();
t3.start();
t1.join();
t2.join();
t3.join();
return ;
}
如果用多态的話,可以用
vector
來儲存父類指針,并初始化指向子類引用,不過使用
vector<Thread*>
我們時常會有困惑,那就是vector作為棧上變量,其程式結束變量生命期結束,而容器中的指針所指向的對象需要我們手動去
delete
,這樣就會容易出錯。boost庫中提供shared_ptr(c++11已經加入std),可以避免這種記憶體洩露的錯誤:vector生命期結束,
shared_ptr
釋放,對象的引用計數變為0,也就自動釋放資源了。
//main.cpp
{
vector< shared_ptr<Thread> > t();
t[].reset(new WatchCount());
t[].reset(new IncCount());
t[].reset(new IncCount());
for(int i=;i<;i++)
{
t[i]->start();
}
for(int i=;i<;i++)
{
t[i]->join();
}
}//debug
3. 完整代碼
3.1主程式
//main.cpp
#include "Thread.h"
#include "MutexLock.h"
#include "Condition.h"
#include <vector>
#include <memory>
using namespace std;
MutexLock mutex;//互斥鎖
Condition cond(mutex);//條件變量
int count =;
class IncCount : public Thread
{
private:
int id_;
public:
IncCount(int id):id_(id){}
void run()
{
for(int i=;i < ;i ++)
{
{
MutexLockGuard lock(mutex);
count++;
if (count == )
{
cond.notify();
}
std::cout<<"thread : "<<id_<<" count : "<< count << std::endl;
}
sleep();
}
}
};
class WatchCount: public Thread
{
private:
int id_;
public:
WatchCount(int id):id_(id){}
void run()
{
MutexLockGuard lock(mutex);
while(count < )
{
cond.wait();
}
assert(count>=);
count+=;
std::cout<<"thread : "<<id_<<" count : "<< count << std::endl;
}
};
int main()
{
{
vector< shared_ptr<Thread> > t();
t[].reset(new WatchCount());
t[].reset(new IncCount());
t[].reset(new IncCount());
for(int i=;i<;i++)
{
t[i]->start();
}
for(int i=;i<;i++)
{
t[i]->join();
}
}
return ;
}
3.2Makefile
#Makefile
PROGS =main
CLEANFILES = core core.* *.core *.o temp.* *.out typescript* \
*.lc *.lh *.bsdi *.sparc *.uw
all :${PROGS}
CXXFLAGS+=-g -std=c++
main: main.o Thread.o MutexLock.o Condition.o
${CXX} ${CXXFLAGS} -o [email protected] $^ -lpthread
@rm *.o
clean:
rm -f ${PROGS} ${CLEANFILES}
4. 參考
1.《Linux多線程服務端程式設計:使用muduo C++網絡庫》
2.http://www.cnblogs.com/inevermore/p/4008572.html