threadPool example
来源:互联网 发布:程序员 白发老头图片 编辑:程序博客网 时间:2024/05/29 19:32
Thread Pools are useful when you need to limit the number of threads running in your application at the same time. There is aperformance overhead associated with starting a new thread, and each thread is also allocated some memory for its stack etc.
Instead of starting a new thread for every task to execute concurrently, the task can be passed to a thread pool. As soon as the pool has any idle threads the task is assigned to one of them and executed. Internally the tasks are inserted into a Blocking Queue which the threads in the pool are dequeuing from. When a new task is inserted into the queue one of the idle threads will dequeue it successfully and execute it. The rest ofthe idle threads in the pool will be blocked waiting to dequeue tasks.
Thread pools are often used in multi threaded servers. Each connection arriving at the server via the network is wrapped as a task and passed on to a thread pool. The threads in the thread pool will process the requests on the connections concurrently. A later trail will get into detail about implementing multithreaded servers in c++.
#include <stdio.h>#include <queue>#include <unistd.h>#include <pthread.h>#include <stdlib.h>// Base task for Tasks// run() should be overloaded and expensive calculations done there// showTask() is for debugging and can be deleted if not usedclass Task {public: Task() {} virtual ~Task() {} virtual void run()=0; virtual void showTask()=0;};// Wrapper around std::queue with some mutex protectionclass WorkQueue {public: WorkQueue() { // Initialize the mutex protecting the queue pthread_mutex_init(&qmtx,0); // wcond is a condition variable that's signaled // when new work arrives pthread_cond_init(&wcond, 0); } ~WorkQueue() { // Cleanup pthreads pthread_mutex_destroy(&qmtx); pthread_cond_destroy(&wcond); } // Retrieves the next task from the queue Task *nextTask() { // The return value Task *nt = 0; // Lock the queue mutex pthread_mutex_lock(&qmtx); // Check if there's work if (finished && tasks.size() == 0) { // If not return null (0) nt = 0; } else { // Not finished, but there are no tasks, so wait for // wcond to be signalled if (tasks.size()==0) { <span style="color:#ff0000;">//No task ,block! Upon successful return,</span> <span style="color:#ff0000;">the mutex shall have been locked and shall be owned by the calling thread</span>. pthread_cond_wait(&wcond, &qmtx); } // get the next task nt = tasks.front(); tasks.pop(); // For debugging if (nt) nt->showTask(); } // Unlock the mutex and return pthread_mutex_unlock(&qmtx); return nt; } // Add a task void addTask(Task *nt) { // Only add the task if the queue isn't marked finished if (!finished) { // Lock the queue,if all thread busy pthread_mutex_lock(&qmtx); // Add the task tasks.push(nt); // signal there's new work pthread_cond_signal(&wcond); // Unlock the mutex pthread_mutex_unlock(&qmtx); } } // Mark the queue finished void finish() { pthread_mutex_lock(&qmtx); finished = true; // Signal the condition variable in case any threads are waiting pthread_cond_signal(&wcond); pthread_mutex_unlock(&qmtx); } // Check if there's work bool hasWork() { return (tasks.size()>0); } private: std::queue<Task*> tasks; bool finished; pthread_mutex_t qmtx; pthread_cond_t wcond;};// Function that retrieves a task from a queue, runs it and deletes itstatic void *getWork(void* param) { Task *mw = 0; WorkQueue *wq = (WorkQueue*)param; while (mw = wq->nextTask()) { mw->run(); delete mw; } return 0;}class ThreadPool {public: // Allocate a thread pool and set them to work trying to get tasks ThreadPool(int n) : _numThreads(n) { printf("Creating a thread pool with %d threads\n", n); threads = new pthread_t[n]; for (int i=0; i< n; ++i) { pthread_create(&(threads[i]), 0, getWork, &workQueue); } } // Wait for the threads to finish, then delete them ~ThreadPool() { workQueue.finish(); waitForCompletion(); for (int i=0; i<_numThreads; ++i) { pthread_join(threads[i], 0); } delete [] threads; } // Add a task void addTask(Task *nt) { workQueue.addTask(nt); } // Tell the tasks to finish and return void finish() { workQueue.finish(); } // Checks if there is work to do bool hasWork() { return workQueue.hasWork(); } // Super inefficient way to wait for all tasks to finish void waitForCompletion() { while (workQueue.hasWork()) {} } private: pthread_t *threads; int _numThreads; WorkQueue workQueue;};// stdout is a shared resource, so protected it with a mutexstatic pthread_mutex_t console_mutex = PTHREAD_MUTEX_INITIALIZER;// Debugging functionvoid showTask(int n) { pthread_mutex_lock(&console_mutex); printf("Adding fib(%d)\n", n); pthread_mutex_unlock(&console_mutex);}// Task to compute fibonacci numbers// It's more efficient to use an iterative algorithm, but// the recursive algorithm takes longer and is more interesting// than sleeping for X seconds to show parrallelismclass FibTask : public Task {public: FibTask(int n) : Task(), _n(n) {} ~FibTask() { // Debug prints pthread_mutex_lock(&console_mutex); printf("tid(%d) - fibd(%d) being deleted\n", pthread_self(), _n); pthread_mutex_unlock(&console_mutex); } virtual void run() { // Note: it's important that this isn't contained in the console mutex lock long long val = innerFib(_n); // Show results pthread_mutex_lock(&console_mutex); printf("Fibd %d = %lld\n",_n, val); pthread_mutex_unlock(&console_mutex); // The following won't work in parrallel: // pthread_mutex_lock(&console_mutex); // printf("Fibd %d = %lld\n",_n, innerFib(_n)); // pthread_mutex_unlock(&console_mutex); } virtual void showTask() { // More debug printing pthread_mutex_lock(&console_mutex); printf("thread %d computing fibonacci %d\n", pthread_self(), _n); pthread_mutex_unlock(&console_mutex); }private: // Slow computation of fibonacci sequence // To make things interesting, and perhaps imporove load balancing, these // inner computations could be added to the task queue // Ideally set a lower limit on when that's done // (i.e. don't create a task for fib(2)) because thread overhead makes it // not worth it long long innerFib(long long n) { if (n<=1) { return 1; } return innerFib(n-1) + innerFib(n-2); } long long _n;};int main(int argc, char *argv[]) { // Create a thread pool ThreadPool *tp = new ThreadPool(12); // Create work for it for (int i=0;i<100; ++i) { int rv = rand() % 50 + 1; showTask(rv); tp->addTask(new FibTask(rv)); // wait for long-time calculation of thread run sleep(1); } // Finish up tp->finish(); // Delete it delete tp; printf("Done with all work!\n");}
- threadPool example
- threadpool
- ThreadPool
- threadPool
- threadpool
- ThreadPool
- threadpool
- threadpool
- ThreadPool
- ThreadPool
- ThreadPool
- ThreadPool
- ThreadPool
- ThreadPool
- ThreadPool
- threadpool
- ThreadPool
- ThreadPool
- 使用Openjdk7编译android源码出现"Could not initialize NSS"错误的解决办法
- nginx安装配置记录
- 用shader在love2d里实现精灵描边效果
- C与指针
- java--图形界面(2)
- threadPool example
- java加密 MessageDigest(一)
- 27.1.1 图表控件概述
- 简易指南针的实现
- 杂七杂八
- BLOB/ClOB存储图片、文档与视频
- 如何解决win10与Ubuntu16.04时间不同步的问题
- $.each的函数使用
- solr4.6多核配置