Main MRPT website > C++ reference for MRPT 1.5.6
threads.cpp
Go to the documentation of this file.
1 /* +---------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2017, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +---------------------------------------------------------------------------+ */
9 
10 #include "base-precomp.h" // Precompiled headers
11 
12 #include <mrpt/system/threads.h>
14 
15 #include <mrpt/utils/CTicTac.h>
16 #include <mrpt/synch/CSemaphore.h>
17 
18 #ifdef MRPT_OS_WINDOWS
19  #include <conio.h>
20  #include <windows.h>
21  #include <process.h>
22  #include <tlhelp32.h>
23  #include <sys/utime.h>
24  #include <io.h>
25  #include <direct.h>
26 #else
27  #include <pthread.h>
28  #include <termios.h>
29  #include <unistd.h>
30  #include <sys/select.h>
31  #include <sys/time.h>
32  #include <time.h>
33  #include <unistd.h>
34  #include <utime.h>
35  #include <errno.h>
36  #include <signal.h>
37  #include <string.h> // strerror()
38 #endif
39 
40 #include <fstream>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #ifdef MRPT_OS_APPLE
44  #include <sys/sysctl.h>
45  #include <mach/mach_init.h>
46  #include <mach/thread_act.h>
47 #endif
48 
49 using namespace mrpt;
50 using namespace mrpt::utils;
51 using namespace mrpt::system;
52 using namespace std;
53 
54 /*---------------------------------------------------------------
55  sleep
56 ---------------------------------------------------------------*/
58 {
59 #ifdef MRPT_OS_WINDOWS
60  Sleep( time_ms );
61 #else
62  // We will wake up on signals: Assure the desired time has passed:
63  CTicTac tictac;
64  tictac.Tic();
65  int timeLeft_ms = time_ms - (int)(tictac.Tac()*1000);
66  while ( timeLeft_ms>0 )
67  {
68  usleep( timeLeft_ms * 1000 );
69  timeLeft_ms = time_ms - (int)(tictac.Tac()*1000);
70  }
71 #endif
72 }
73 
74 /*---------------------------------------------------------------
75  createThread
76 ---------------------------------------------------------------*/
77 namespace mrpt
78 {
79  namespace system
80  {
82  {
83  #ifdef MRPT_OS_WINDOWS
84  TAuxThreadLaucher() : ptrFunc(NULL),param(NULL),win_sem(0,10)
85  {
86  }
87  #else
88  TAuxThreadLaucher() : ptrFunc(NULL),param(NULL) { };
89  #endif
90  void (*ptrFunc) (void *);
91  void *param;
92 
93  #ifdef MRPT_OS_WINDOWS
94  // These for windows only:
95  unsigned long myWindowsId;
96  synch::CSemaphore win_sem;
97  #endif
98  };
99 
101  {
102  try
103  {
104  TAuxThreadLaucher *d = reinterpret_cast<TAuxThreadLaucher*>(param);
105 
106  TAuxThreadLaucher localCopy = *d;
107 
108  #ifdef MRPT_OS_WINDOWS
109  // Signal that the thread has started:
110  d->myWindowsId = (unsigned long)GetCurrentThreadId();
111  d->win_sem.release();
112  // Our parent thread will release the memory of "param".
113  #else
114  // LINUX: We have to free here this memory:
115  delete d;
116  d = NULL;
117  #endif
118 
119  // Now start the user code:
120  localCopy.ptrFunc( localCopy.param );
121  }
122  catch(std::exception &e)
123  {
124  std::cout << "Exception in [auxiliary_thread_launcher_LIN/WIN]!!!:\n" << e.what();
125  }
126  catch(...)
127  {
128  std::cout << "Untyped exception in [auxiliary_thread_launcher_LIN/WIN]!!!\n";
129  }
130  return NULL;
131  }
132 
134  {
136  }
137  } // end namespace
138 } // end namespace
139 
140 
142  void ( *func )( void * ),
143  void *param
144  )
145 {
146  MRPT_START
147 
148  TAuxThreadLaucher *auxData=new TAuxThreadLaucher();
149  auxData->ptrFunc = func;
150  auxData->param = param;
151 
152 #ifdef MRPT_OS_WINDOWS
153  TThreadHandle threadHandle;
154 
155  HANDLE h= (HANDLE)_beginthread( auxiliary_thread_launcher_WIN,0, auxData);
156  if (h== ((HANDLE) -1))
157  {
158  delete auxData;
159  THROW_EXCEPTION("Error creating new thread");
160  }
161 
162  threadHandle.hThread = h;
163 
164  // Wait until the thread starts so we know its ID:
165  auxData->win_sem.waitForSignal();
166  threadHandle.idThread = auxData->myWindowsId;
167 
168  delete auxData; auxData = NULL;
169 
170  return threadHandle;
171 
172 #else
173  TThreadHandle threadHandle;
174 
175  pthread_t newThreadId;
176  int iRet = pthread_create( &newThreadId,NULL,auxiliary_thread_launcher_LIN,auxData);
177  ASSERT_(iRet==0);
178 
179  threadHandle.idThread = (unsigned long)newThreadId;
180  return threadHandle;
181 #endif
182 
183  MRPT_END
184 }
185 
186 
187 /*---------------------------------------------------------------
188  joinThread
189 ---------------------------------------------------------------*/
190 void mrpt::system::joinThread( const TThreadHandle &threadHandle )
191 {
192  if (threadHandle.isClear()) return;
193 #ifdef MRPT_OS_WINDOWS
194  int prio = GetThreadPriority((HANDLE) threadHandle.hThread);
195  if (THREAD_PRIORITY_ERROR_RETURN==prio)
196  return; // It seems this is not a running thread...
197 
198  DWORD ret = WaitForSingleObject( (HANDLE) threadHandle.hThread , INFINITE );
199  if (ret!=WAIT_OBJECT_0)
200  cerr << "[mrpt::system::joinThread] Error waiting for thread completion!" << endl;
201 #elif defined(MRPT_OS_APPLE)
202  pthread_join(reinterpret_cast<pthread_t>(threadHandle.idThread), NULL);
203 #else
204  pthread_join(threadHandle.idThread, NULL);
205 #endif
206 }
207 
208 /*---------------------------------------------------------------
209  getCurrentThreadId
210 ---------------------------------------------------------------*/
212 {
213 #ifdef MRPT_OS_WINDOWS
214  return GetCurrentThreadId();
215 
216 /* Jerome Monceaux 2011/03/08: bilock@gmail.com
217  * The next precompilation directive didn't compile under osx
218  * added defined(MRPT_OS_APPLE) solved the probleme
219  */
220 //#elif MRPT_OS_APPLE
221 #elif defined(MRPT_OS_APPLE)
222  return reinterpret_cast<unsigned long>(pthread_self());
223 #else
224  return pthread_self();
225 #endif
226 }
227 
228 /*---------------------------------------------------------------
229  getCurrentThreadHandle
230 ---------------------------------------------------------------*/
232 {
233  TThreadHandle h;
234 #ifdef MRPT_OS_WINDOWS
235  // Win32:
236  h.hThread = GetCurrentThread();
237  h.idThread = GetCurrentThreadId();
238 #elif defined(MRPT_OS_APPLE)
239  h.idThread = reinterpret_cast<long unsigned int>(pthread_self());
240 #else
241  // pthreads:
242  h.idThread = pthread_self();
243 #endif
244  return h;
245 }
246 
247 /*---------------------------------------------------------------
248  changeThreadPriority
249 ---------------------------------------------------------------*/
251  const TThreadHandle &threadHandle,
252  TThreadPriority priority )
253 {
254 #ifdef MRPT_OS_WINDOWS
255  // TThreadPriority is defined to agree with numbers expected by Win32 API:
256  SetThreadPriority( threadHandle.hThread, priority);
257 #else
258 
259  const pthread_t tid =
260  #ifdef MRPT_OS_APPLE
261  reinterpret_cast<pthread_t>(threadHandle.idThread);
262  #else
263  threadHandle.idThread;
264  #endif
265 
266  int ret, policy;
267  struct sched_param param;
268 
269  if (0!=(ret=pthread_getschedparam(tid,&policy,&param))) {
270  cerr << "[mrpt::system::changeThreadPriority] Warning: Failed call to pthread_getschedparam (error: `" << strerror(ret) << "`)" << endl;
271  return;
272  }
273 
274  policy = SCHED_RR;
275  int min_prio = sched_get_priority_min(policy), max_prio = sched_get_priority_max(policy);
276  if (min_prio<0) min_prio=1; // Just in case of error to calls above (!)
277  if (max_prio<0) max_prio=99;
278 
279  int prio = 0;
280  switch(priority)
281  {
282  case tpLowests: prio=min_prio; break;
283  case tpLower : prio=(max_prio+3*min_prio)/4; break;
284  case tpLow : prio=(max_prio+2*min_prio)/3; break;
285  case tpNormal: prio=(max_prio+min_prio )/2; break;
286  case tpHigh : prio=(2*max_prio+min_prio)/3; break;
287  case tpHigher: prio=(3*max_prio+min_prio)/4; break;
288  case tpHighest: prio=max_prio; break;
289  }
290 
291  param.sched_priority = prio;
292  if (0!=(ret=pthread_setschedparam(tid, policy, &param))) {
293  cerr << "[mrpt::system::changeThreadPriority] Warning: Failed call to pthread_setschedparam (error: `" << strerror(ret) << "`)" << endl;
294  return;
295  }
296 
297 #endif
298 }
299 
300 /*---------------------------------------------------------------
301  changeCurrentProcessPriority
302 ---------------------------------------------------------------*/
304 {
305 #ifdef MRPT_OS_WINDOWS
306  DWORD dwPri;
307  switch (priority)
308  {
309  case ppIdle: dwPri = IDLE_PRIORITY_CLASS; break;
310  case ppNormal: dwPri = NORMAL_PRIORITY_CLASS; break;
311  case ppHigh: dwPri = HIGH_PRIORITY_CLASS; break;
312  case ppVeryHigh: dwPri= REALTIME_PRIORITY_CLASS; break;
313  default:
314  THROW_EXCEPTION("Invalid priority value");
315  }
316  SetPriorityClass( GetCurrentProcess(), dwPri );
317 #else
318  int nice_val;
319  switch (priority)
320  {
321  case ppIdle: nice_val =+19; break;
322  case ppNormal: nice_val = 0; break;
323  case ppHigh: nice_val =-10; break;
324  case ppVeryHigh: nice_val =-20; break;
325  default:
326  THROW_EXCEPTION("Invalid priority value");
327  }
328  errno=0;
329  const int ret = nice(nice_val);
330  if (ret==-1 && errno==EPERM) {
331  std::cerr << "[mrpt::system::changeCurrentProcessPriority] Error calling nice(): Not enough permissions.\n";
332  }
333 #endif
334 }
335 
336 /*---------------------------------------------------------------
337  mrpt::system::getCurrentThreadTimes
338 ---------------------------------------------------------------*/
340  time_t &creationTime,
341  time_t &exitTime,
342  double &cpuTime )
343 {
344  MRPT_START
345 
346 #ifdef MRPT_OS_WINDOWS
347  FILETIME timCreat,timExit, timKernel, timUser;
348  uint64_t t;
349 
350  HANDLE threadHandle;
351 
352 #if !defined(HAVE_OPENTHREAD) // defined(_MSC_VER) && (_MSC_VER<1300)
353  // In MSVC6/GCC the ID is just the HANDLE:
354  threadHandle = reinterpret_cast<HANDLE>( mrpt::system::getCurrentThreadId() );
355 #else
356  // Get the handle from the ID:
357  threadHandle = OpenThread( READ_CONTROL | THREAD_QUERY_INFORMATION, FALSE, GetCurrentThreadId() ); // threadId);
358  if (!threadHandle) THROW_EXCEPTION("Cannot open the thread with the given 'threadId'");
359 #endif
360 
361  if (!GetThreadTimes( threadHandle , &timCreat, &timExit, &timKernel, &timUser ))
362  {
363  CloseHandle(threadHandle);
364  THROW_EXCEPTION("Error accessing thread times!");
365  }
366 
367 #if defined(HAVE_OPENTHREAD) // _MSC_VER) && (_MSC_VER>=1300)
368  // From OpenThread...
369  CloseHandle(threadHandle);
370 #endif
371 
372  // Formula is derived from:
373  // http://support.microsoft.com/kb/167296
374  t = (((uint64_t)timCreat.dwHighDateTime) << 32) | timCreat.dwLowDateTime;
375  creationTime = (t - 116444736000000000ULL)/10000000;
376 
377  t = (((uint64_t)timExit.dwHighDateTime) << 32) | timExit.dwLowDateTime;
378  exitTime = (t - 116444736000000000ULL)/10000000;
379 
380  // CPU time is user+kernel:
381  int64_t t1 = (((uint64_t)timKernel.dwHighDateTime) << 32) | timKernel.dwLowDateTime;
382  int64_t t2 = (((uint64_t)timUser.dwHighDateTime) << 32) | timUser.dwLowDateTime;
383 
384  cpuTime = ((double)(t1+t2)) * 100e-9; // FILETIME counts intervals of 100ns
385 
386 #endif
387 
388 #ifdef MRPT_OS_LINUX
389  MRPT_UNUSED_PARAM(creationTime);
390  MRPT_UNUSED_PARAM(exitTime);
391  // Unix:
392 # ifdef HAVE_GETTID
393  pid_t id = gettid();
394 # else
395  // gettid is:
396  // 186 in 64bit
397  // 224 in 32bit
398  #if MRPT_WORD_SIZE==64
399  pid_t id = (long int)syscall(186);
400  #elif MRPT_WORD_SIZE==32
401  pid_t id = (long int)syscall(224);
402  #else
403  #error MRPT_WORD_SIZE must be 32 or 64.
404  #endif
405 # endif
406 
407  // (JL) Refer to: /usr/src/linux/fs/proc/array.c
408  long unsigned tms_utime=0, tms_stime=0;
409  ifstream is(format("/proc/self/task/%i/stat", id).c_str() );
410 
411  if (is.is_open())
412  {
413  string s;
414  getline(is,s);
415 
416  size_t idx = s.find(")");
417 
418  if (idx!=string::npos)
419  {
420  vector_string tokens;
421  mrpt::system::tokenize( string(s.c_str()+idx+1)," ",tokens);
422 
423  if (tokens.size()>=13)
424  {
425  sscanf(tokens[11].c_str(), "%lu" ,&tms_utime);
426  sscanf(tokens[12].c_str(), "%lu", &tms_stime);
427  }
428  }
429  }
430 
431  // Compute cpuTime:
432  double clockTicksPerSecond = (double)sysconf(_SC_CLK_TCK);
433  if (clockTicksPerSecond>0)
434  cpuTime = (tms_utime + tms_stime) / clockTicksPerSecond;
435 #endif
436 
437 #ifdef MRPT_OS_APPLE
438  thread_basic_info info;
439  mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
440  if(thread_info(mach_thread_self(), THREAD_BASIC_INFO, (thread_info_t)&info, &count)==0)
441  {
442  double utime = info.user_time.seconds + info.user_time.microseconds * 1e-6;
443  double stime = info.system_time.seconds + info.system_time.microseconds * 1e-6;
444  cpuTime = utime + stime;
445  }
446 #endif
447 
448  MRPT_END
449 }
450 
451 /*---------------------------------------------------------------
452  launchProcess
453  ---------------------------------------------------------------*/
455 {
456 #ifdef MRPT_OS_WINDOWS
457  STARTUPINFOA SI;
458  PROCESS_INFORMATION PI;
459 
460  memset(&SI,0,sizeof(STARTUPINFOA) );
461  SI.cb = sizeof(STARTUPINFOA);
462 
463  if (CreateProcessA( NULL, (LPSTR)command.c_str(), NULL, NULL, true, 0, NULL, NULL, &SI, &PI) )
464  {
465  // Wait:
466  WaitForSingleObject( PI.hProcess, INFINITE );
467  return true;
468  } // End of process executed OK
469  else
470  {
471  char str[300];
472  DWORD e = GetLastError();
473 
474  FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,0,e,0,str,sizeof(str), NULL);
475 
476  // ERROR:
477  std::cerr << "[launchProcess] Couldn't spawn process. Error msg: " << str << std::endl;
478  return false;
479  }
480 #else
481  return 0== ::system(command.c_str());
482 #endif
483 } // end launchProcess
484 
485 // Return number of processors in the system
487 {
488  static unsigned int ret = 0;
489 
490  if (!ret)
491  {
492 #ifdef MRPT_OS_WINDOWS
493  SYSTEM_INFO si; // Requires Win200 or above.
494  GetSystemInfo(&si);
495  ret=si.dwNumberOfProcessors;
496  if (ret<1) ret=1;
497 #elif defined(MRPT_OS_APPLE)
498  size_t len=sizeof(int);
499  if(sysctlbyname("hw.logicalcpu", &ret, &len, NULL, 0) != 0)
500  ret = 1; // failed
501 #else
502  // This assumes a Linux kernel 2.6
503  ifstream f;
504  f.open("/proc/cpuinfo");
505  if (!f.is_open())
506  return 1; // No info...
507 
508  std::string lin;
509  unsigned int nProc = 0;
510  while (!f.fail() && !f.eof())
511  {
512  std::getline(f,lin);
513  if (!f.fail() && !f.eof())
514  if (lin.find("processor")!=std::string::npos)
515  nProc++;
516  }
517  ret = nProc ? nProc : 1;
518 #endif
519  }
520  return ret;
521 }
522 
523 /*---------------------------------------------------------------
524  exitThread
525  ---------------------------------------------------------------*/
527 {
528 #ifdef MRPT_OS_WINDOWS
529  ExitThread(0);
530 #else
531  pthread_exit(NULL);
532 #endif
533 }
534 
535 /*---------------------------------------------------------------
536  terminateThread
537  ---------------------------------------------------------------*/
539 {
540  if (threadHandle.isClear()) return; // done
541 
542 #ifdef MRPT_OS_WINDOWS
543  TerminateThread(threadHandle.hThread, DWORD(-1));
544 #elif defined(MRPT_OS_APPLE)
545  pthread_cancel(reinterpret_cast<pthread_t>(threadHandle.idThread));
546 #else
547  pthread_cancel(threadHandle.idThread);
548 #endif
549  threadHandle.clear();
550 }
GLuint GLuint GLsizei count
Definition: glext.h:3512
TThreadPriority
The type for cross-platform thread priorities.
Definition: threads.h:80
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values, timewatch, extensions to STL.
Definition: zip.h:16
GLdouble GLdouble t
Definition: glext.h:3610
unsigned long BASE_IMPEXP getCurrentThreadId() MRPT_NO_THROWS
Returns the ID of the current thread.
Definition: threads.cpp:211
void BASE_IMPEXP changeCurrentProcessPriority(TProcessPriority priority)
Change the priority of the given process (it applies to all the threads, plus independent modifiers f...
Definition: threads.cpp:303
This namespace provides a OS-independent interface to many useful functions: filenames manipulation...
Definition: math_frwds.h:29
void BASE_IMPEXP changeThreadPriority(const TThreadHandle &threadHandle, TThreadPriority priority)
Change the priority of the given thread - for Windows, see also changeCurrentProcessPriority() ...
Definition: threads.cpp:250
#define THROW_EXCEPTION(msg)
TThreadHandle BASE_IMPEXP getCurrentThreadHandle() MRPT_NO_THROWS
Returns a handle to the current thread.
Definition: threads.cpp:231
unsigned int BASE_IMPEXP getNumberOfProcessors()
Return the number of processors ("cores"), or 1 if it cannot be determined.
Definition: threads.cpp:486
#define MRPT_NO_THROWS
C++11 noexcept: Used after member declarations.
STL namespace.
TProcessPriority
The type for cross-platform process (application) priorities.
Definition: threads.h:70
GLdouble s
Definition: glext.h:3602
GLenum GLsizei len
Definition: glext.h:4349
void Tic()
Starts the stopwatch.
Definition: CTicTac.cpp:77
bool BASE_IMPEXP launchProcess(const std::string &command)
Executes the given command (which may contain a program + arguments), and waits until it finishes...
Definition: threads.cpp:454
void BASE_IMPEXP getCurrentThreadTimes(time_t &creationTime, time_t &exitTime, double &cpuTime)
Returns the creation and exit times of the current thread and its CPU time consumed.
Definition: threads.cpp:339
std::vector< std::string > vector_string
A type for passing a vector of strings.
Definition: types_simple.h:30
void * auxiliary_thread_launcher_LIN(void *param)
Definition: threads.cpp:100
#define MRPT_END
#define MRPT_UNUSED_PARAM(a)
Can be used to avoid "not used parameters" warnings from the compiler.
__int64 int64_t
Definition: rptypes.h:51
void BASE_IMPEXP sleep(int time_ms) MRPT_NO_THROWS
An OS-independent method for sending the current thread to "sleep" for a given period of time...
Definition: threads.cpp:57
#define FALSE
Definition: jmorecfg.h:227
This class implements a high-performance stopwatch.
Definition: CTicTac.h:24
std::string BASE_IMPEXP format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
Definition: format.cpp:21
bool isClear() const
Returns true if the handle is uninitialized.
Definition: threads.h:64
GLsizei const GLchar ** string
Definition: glext.h:3919
#define MRPT_START
unsigned __int64 uint64_t
Definition: rptypes.h:52
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
backing_store_ptr info
Definition: jmemsys.h:170
This structure contains the information needed to interface the threads API on each platform: ...
Definition: threads.h:25
double Tac()
Stops the stopwatch.
Definition: CTicTac.cpp:92
#define ASSERT_(f)
void BASE_IMPEXP terminateThread(TThreadHandle &threadHandle) MRPT_NO_THROWS
Terminate a thread, giving it no choice to delete objects, etc (use only as a last resource) ...
Definition: threads.cpp:538
typedef void(APIENTRYP PFNGLBLENDCOLORPROC)(GLclampf red
TThreadHandle BASE_IMPEXP createThreadImpl(void(*func)(void *), void *param)
Definition: threads.cpp:141
GLfloat param
Definition: glext.h:3705
void BASE_IMPEXP tokenize(const std::string &inString, const std::string &inDelimiters, std::deque< std::string > &outTokens, bool skipBlankTokens=true) MRPT_NO_THROWS
Tokenizes a string according to a set of delimiting characters.
A semaphore for inter-thread synchronization.
Definition: CSemaphore.h:28
void BASE_IMPEXP exitThread() MRPT_NO_THROWS
Explicit close of the current (running) thread.
Definition: threads.cpp:526
void auxiliary_thread_launcher_WIN(void *param)
Definition: threads.cpp:133
void BASE_IMPEXP joinThread(const TThreadHandle &threadHandle)
Waits until the given thread ends.
Definition: threads.cpp:190



Page generated by Doxygen 1.8.14 for MRPT 1.5.6 Git: 4c65e8431 Tue Apr 24 08:18:17 2018 +0200 at lun oct 28 01:35:26 CET 2019