parallel.cpp
00001 #include "parallel.h"
00002
00003 #ifdef WIN32
00004 # include <windows.h>
00005 #else
00006 # include <unistd.h>
00007 #endif
00008
00009 #include <QThread>
00010 #include <QSemaphore>
00011
00012 #include <QQueue>
00013 #include <QMutex>
00014 #include <QMutexLocker>
00015
00016 #include <cassert>
00017 #include <iostream>
00018
00019 #include <qatomic.h>
00020
00021 namespace parallel
00022 {
00023 using std::cout;
00024 using std::endl;
00025
00026 class EvalThread;
00027
00028 struct ThreadPoolImpl
00029 {
00030 ThreadPoolImpl()
00031 : nbThreads(0)
00032 { }
00033
00034 QSemaphore eval_wait;
00035 QMutex eval_mutex;
00036 QSemaphore result_ready;
00037 QQueue<const ThreadEval*> eval_queue;
00038 QQueue<EvalThread*> to_delete;
00039 int nbThreads;
00040 };
00041
00042 class EvalThread : public QThread
00043 {
00044 public:
00045 EvalThread(ThreadPoolImpl* c)
00046 : QThread(0)
00047 , com(c)
00048 { }
00049
00050 protected:
00051 void run()
00052 {
00053 {
00054 QMutexLocker locker(&com->eval_mutex);
00055 cout << "*** EvalThread started: " << (void*)currentThreadId() << " ***" << endl;
00056 }
00057 while(1)
00058 {
00059 const ThreadEval* fct;
00060 com->eval_wait.acquire();
00061 if(com->eval_queue.empty())
00062 break;
00063 {
00064 QMutexLocker locker(&com->eval_mutex);
00065 fct = com->eval_queue.dequeue();
00066 }
00067 (*fct)();
00068 com->result_ready.release();
00069 }
00070 {
00071 QMutexLocker locker(&com->eval_mutex);
00072 cout << "--- EvalThread stoped: " << (void*)currentThreadId() << " ---" << endl;
00073 com->to_delete.enqueue(this);
00074 com->result_ready.release();
00075 }
00076 }
00077
00078 ThreadPoolImpl *com;
00079
00080 };
00081
00082 ThreadPool::ThreadPool()
00083 : impl(new ThreadPoolImpl())
00084 , nbComputations(0)
00085 {
00086 setNbThreadsToDefault();
00087 }
00088
00089 ThreadPool::~ThreadPool()
00090 {
00091 clear();
00092 delete impl;
00093 }
00094
00095 void ThreadPool::clear()
00096 {
00097 setNbThreads(0);
00098 }
00099
00100 void ThreadPool::thread_eval( const ThreadEval* fct )
00101 {
00102 nbComputations++;
00103 impl->eval_queue.enqueue(fct);
00104 impl->eval_wait.release();
00105 }
00106
00107 void ThreadPool::join()
00108 {
00109 impl->result_ready.acquire(this->nbComputations);
00110 this->nbComputations = 0;
00111 assert(impl->eval_queue.isEmpty());
00112 }
00113
00114 void ThreadPool::setNbThreads( int n )
00115 {
00116 int nt = impl->nbThreads;
00117 cout << "Changing thread number from " << nt << " to " << n << endl;
00118 if(n > nt)
00119 {
00120 for(int i = nt ; i < n ; ++i)
00121 {
00122 cout << "Creating thread " << i << endl;
00123 EvalThread *t = new EvalThread(impl);
00124 t->start();
00125 }
00126 }
00127 else if(n < nt)
00128 {
00129 join();
00130 impl->eval_wait.release(nt-n);
00131 impl->result_ready.acquire(nt-n);
00132 while(!impl->to_delete.isEmpty())
00133 {
00134 EvalThread* th = impl->to_delete.dequeue();
00135 th->wait();
00136 delete th;
00137 }
00138 }
00139 impl->nbThreads = n;
00140 }
00141
00142 int ThreadPool::nbProcessors()
00143 {
00144 return QThread::idealThreadCount();
00145 }
00146
00147 int ThreadPool::nbThreads()
00148 {
00149 return impl->nbThreads;
00150 }
00151
00152 void ThreadPool::setNbThreadsToDefault()
00153 {
00154 int n = this->nbProcessors();
00155 if( n < 2 )
00156 n = 0;
00157 this->setNbThreads(n);
00158 }
00159 }