As is mentioned in my pervious article Thread Management Class, I shall introduce a simple thread pool implemented by the CThread class. For more information about class IRunnable and CThread, please link to:
http://blog.csdn.net/sooner01/archive/2008/12/29/3639936.aspx
Firstly the class initializes some threads, and has the threads waiting to run some task. Then restore some task in to a queue, once the a task in submitted, a blocking thread is waken to run the task.
We can see the CSimpleThreadPool is derived from the IRunnable, and the virtual function run() is implement to be called by all thread function.
Here is the source code of the thread pool class.
//---------------------------- CLASS ---------------------------------------------------------- // A class containing a collection of CThreadTask's. // Every CThreadTask will execute same CSimpleThreadPool::run() method. class CSimpleThreadPool: public IRunnable { private: QMutex m_qMutex; // sync the access to m_PQueue vector<CThread*> m_arrThreadTasks; // restore the working thread mpriority_queue<CPriorityTask> m_PQueue; // restore the task QSemaphore *m_pTaskQSemaphore; // notify the working thread
// Method will return a task from the queue, // if there are no tasks in the queue, method will return NULL. IRunnable *get() { IRunnable *ret = NULL;
m_qMutex.Lock(); if (!m_PQueue.empty()) { CPriorityTask t = m_PQueue.top(); m_PQueue.pop(); ret = t.getTask(); } m_qMutex.Unlock(); return ret; };
public: // How many threads are in the collection. int threads() const { return m_arrThreadTasks.size(); };
// Method starts pool's threads. void startAll() { for (int i = 0; i < m_arrThreadTasks.size(); i++) { m_arrThreadTasks[i]->start(); } };
// Constructor creates the thread pool and sets capacity for the task queue. CSimpleThreadPool(unsigned int nThreadsCount, unsigned int nQueueCapacity = 16): m_qMutex(), m_PQueue(), m_pTaskQSemaphore(NULL) { int i; CThread *thTask = NULL;
if (nThreadsCount <= 0) throw "Invalid number of threads supplied."; if (nQueueCapacity <= 0) throw "Invalid capacity supplied.";
// Set initial capacity of the tasks Queue. // seems doesn't work m_PQueue.reserve(nQueueCapacity);
// Initialize thread pool. for (i = 0; i < nThreadsCount; i++) { thTask = new CThread(this); if (thTask != NULL) m_arrThreadTasks.push_back(thTask); }
// initialize the task semaphore m_pTaskQSemaphore = new QSemaphore(0, nQueueCapacity); if (NULL == m_pTaskQSemaphore) throw "Semaphore initialization error!"; };
// Submit a new task to the pool void submit(IRunnable *pRunObj, int nPriority = 0) { if (this == pRunObj) throw "Self referencing not allowed.";
m_qMutex.Lock(); m_PQueue.push(CPriorityTask(pRunObj, nPriority)); m_qMutex.Unlock();
// call a thread to work for new task m_pTaskQSemaphore->Dec(); };
// Method will execute task's run() method within its CThread context. virtual void run() { IRunnable *task;
while (!CThread::currentThread().isInterrupted()) {
// wait for a task m_pTaskQSemaphore->Inc();
// Get a task from the queue. task = get();
// Execute the task. if (task != NULL) task->run(); } };
virtual ~CSimpleThreadPool() { vector<CThread*>::iterator itPos = m_arrThreadTasks.begin();
for (; itPos < m_arrThreadTasks.end(); itPos++) delete *itPos; m_arrThreadTasks.clear();
while (!m_PQueue.empty()) { m_PQueue.pop(); }
if (m_pTaskQSemaphore != NULL) delete m_pTaskQSemaphore; };
// Method signals threads to stop and waits for termination void shutdown() { for (int i = 0; i < m_arrThreadTasks.size(); i++) { m_arrThreadTasks[i]->interrupt(); } // stop threads waiting m_pTaskQSemaphore->Dec(m_arrThreadTasks.size());
// have all threads closed for (int i = 0; i < m_arrThreadTasks.size(); i++) { m_arrThreadTasks[i]->join(); } }; }; |
How to use
It’s very easy to use, at the beginning you need to design an IRunnable class and implement the virtual function run(), then new a CSimpleThreadPool, start all the working thread by calling startAll(), and finally submit some task to the thread pool.
Here is the sample code:
// start all thread void CThreadClassTestDlg::OnBnClickedButtonStart() { CSimpleThreadPool *pCSimpleThreadPool = NULL; pCSimpleThreadPool = new CSimpleThreadPool(5);
if (NULL == pCSimpleThreadPool) return;
pCSimpleThreadPool->startAll();
Increase *pIncrease = NULL; pIncrease = new Increase(&this->m_CEdit_counter); g_pCSimpleThreadPool->submit(pIncrease); } |