JDFTx  1.2.0
Thread.h
Go to the documentation of this file.
1 /*-------------------------------------------------------------------
2 Copyright 2011 Ravishankar Sundararaman
3 
4 This file is part of JDFTx.
5 
6 JDFTx is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10 
11 JDFTx is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with JDFTx. If not, see <http://www.gnu.org/licenses/>.
18 -------------------------------------------------------------------*/
19 
20 #ifndef JDFTX_CORE_THREAD_H
21 #define JDFTX_CORE_THREAD_H
22 
25 
31 #include <core/Util.h>
32 #include <thread>
33 #include <mutex>
34 #include <unistd.h>
35 
36 extern int nProcsAvailable;
37 
49 
52 
53 
71 template<typename Callable,typename ... Args>
72 void threadLaunch(int nThreads, Callable* func, size_t nJobs, Args... args);
73 
78 template<typename Callable,typename ... Args>
79 void threadLaunch(Callable* func, size_t nJobs, Args... args);
80 
81 
84 {
85 public:
90  AutoThreadCount(int minThreads=1, int minStats=3, const char* name=0, FILE* fpLog=stdout);
91  ~AutoThreadCount();
92 private:
93  template<typename Callable,typename ... Args>
94  friend void threadLaunch(AutoThreadCount*, Callable*, size_t, Args... args);
95 
96  int getThreadCount();
97  void submitTime(int, double);
98  double* time; int* count; int minThreads, nMax, nOpt, minStats; bool settled;
99  char* name; FILE* fpLog;
100 };
101 
107 template<typename Callable,typename ... Args>
108 void threadLaunch(AutoThreadCount*, Callable* func, size_t nJobs, Args... args);
109 
110 
128 template<typename Callable,typename ... Args>
129 void threadedLoop(Callable* func, size_t nIter, Args... args);
130 
131 
138 template<typename Callable,typename ... Args>
139 double threadedAccumulate(Callable* func, size_t nIter, Args... args);
140 
142 
143 
144 //###################################################################################################
145 //#### Implementation ####
146 //##########################
148 
149 template<typename Callable,typename ... Args>
150 void threadLaunch(int nThreads, Callable* func, size_t nJobs, Args... args)
151 { if(nThreads<=0) nThreads = shouldThreadOperators() ? nProcsAvailable : 1;
152  if(nThreads>1) suspendOperatorThreading(); //Prevent func and anything it calls from launching nested threads
153  std::thread** tArr = new std::thread*[nThreads-1];
154  for(int t=0; t<nThreads; t++)
155  { size_t i1 = (nJobs>0 ? ( t * nJobs)/nThreads : t);
156  size_t i2 = (nJobs>0 ? ((t+1) * nJobs)/nThreads : nThreads);
157  if(t<nThreads-1) tArr[t] = new std::thread(func, i1, i2, args...);
158  else (*func)(i1, i2, args...);
159  }
160  for(int t=0; t<nThreads-1; t++)
161  { tArr[t]->join();
162  delete tArr[t];
163  }
164  delete[] tArr;
165  if(nThreads>1) resumeOperatorThreading(); //End nested threading guard section
166 }
167 
168 template<typename Callable,typename ... Args>
169 void threadLaunch(Callable* func, size_t nJobs, Args... args)
170 { threadLaunch(0, func, nJobs, args...);
171 }
172 
173 
174 template<typename Callable,typename ... Args>
175 void threadLaunch(AutoThreadCount* atc, Callable* func, size_t nJobs, Args... args)
176 { if(!atc)
177  threadLaunch(func, nJobs, args...);
178  else
179  { int nThreads = atc->getThreadCount();
180  double runTime = clock_us();
181  threadLaunch(nThreads, func, nJobs, args...);
182  runTime = clock_us() - runTime;
183  atc->submitTime(nThreads, runTime);
184  }
185 }
186 
187 
188 template<typename Callable,typename ... Args>
189 void threadedLoop_sub(size_t iMin, size_t iMax, Callable* func, Args... args)
190 { for(size_t i=iMin; i<iMax; i++) (*func)(i, args...);
191 }
192 template<typename Callable,typename ... Args>
193 void threadedLoop(Callable* func, size_t nIter, Args... args)
194 { threadLaunch(threadedLoop_sub<Callable,Args...>, nIter, func, args...);
195 }
196 
197 template<typename Callable,typename ... Args>
198 void threadedAccumulate_sub(size_t iMin, size_t iMax, Callable* func, double* accumTot, std::mutex* m, Args... args)
199 { double accum=0.0;
200  for(size_t i=iMin; i<iMax; i++) accum += (*func)(i, args...);
201  m->lock(); *accumTot += accum; m->unlock();
202 }
203 template<typename Callable,typename ... Args>
204 double threadedAccumulate(Callable* func, size_t nIter, Args... args)
205 { double accumTot=0.0;
206  std::mutex m;
207  threadLaunch(threadedAccumulate_sub<Callable,Args...>, nIter, func, &accumTot, &m, args...);
208  return accumTot;
209 }
210 
212 #endif // JDFTX_CORE_THREAD_H
friend void threadLaunch(AutoThreadCount *, Callable *, size_t, Args...args)
bool shouldThreadOperators()
void threadLaunch(int nThreads, Callable *func, size_t nJobs, Args...args)
A simple utility for running muliple threads.
void threadedLoop(Callable *func, size_t nIter, Args...args)
A parallelized loop.
void suspendOperatorThreading()
call from multi-threaded top-level code to disable threading within operators called from a parallel ...
Maintain thread timing statistics and automatically choose the optimum number of threads.
Definition: Thread.h:83
AutoThreadCount(int minThreads=1, int minStats=3, const char *name=0, FILE *fpLog=stdout)
Miscellaneous utilities.
int nProcsAvailable
number of available processors (initialized to number of online processors, can be overriden) ...
double threadedAccumulate(Callable *func, size_t nIter, Args...args)
A parallelized loop with an accumulated return value.
void resumeOperatorThreading()
call after a parallel section in top-level code to resume threading within subsequent operator calls ...