Main MRPT website > C++ reference for MRPT 1.5.7
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 
75 {
76  if (threadHandle.m_thread && threadHandle.m_thread->joinable())
77  threadHandle.m_thread->join();
78 }
79 
80 /*---------------------------------------------------------------
81  getCurrentThreadId
82 ---------------------------------------------------------------*/
84 {
85 #ifdef MRPT_OS_WINDOWS
86  return GetCurrentThreadId();
87 #elif defined(MRPT_OS_APPLE)
88  return reinterpret_cast<unsigned long>(pthread_self());
89 #else
90  return pthread_self();
91 #endif
92 }
93 
95 {
96 #ifdef MRPT_OS_WINDOWS
97  // TThreadPriority is defined to agree with numbers expected by Win32 API:
98  SetThreadPriority(GetCurrentThread(), priority);
99 #else
100  const pthread_t tid =
101 #ifdef MRPT_OS_APPLE
102  reinterpret_cast<long unsigned int>(pthread_self());
103 #else
104  pthread_self();
105 #endif
106 
107  int ret, policy;
108  struct sched_param param;
109 
110  if (0 != (ret = pthread_getschedparam(tid, &policy, &param))) {
111  cerr << "[mrpt::system::changeThreadPriority] Warning: Failed call to pthread_getschedparam (error: `" << strerror(ret) << "`)" << endl;
112  return;
113  }
114 
115  policy = SCHED_RR;
116  int min_prio = sched_get_priority_min(policy), max_prio = sched_get_priority_max(policy);
117  if (min_prio<0) min_prio = 1; // Just in case of error to calls above (!)
118  if (max_prio<0) max_prio = 99;
119 
120  int prio = 0;
121  switch (priority)
122  {
123  case tpLowests: prio = min_prio; break;
124  case tpLower: prio = (max_prio + 3 * min_prio) / 4; break;
125  case tpLow: prio = (max_prio + 2 * min_prio) / 3; break;
126  case tpNormal: prio = (max_prio + min_prio) / 2; break;
127  case tpHigh: prio = (2 * max_prio + min_prio) / 3; break;
128  case tpHigher: prio = (3 * max_prio + min_prio) / 4; break;
129  case tpHighest: prio = max_prio; break;
130  }
131 
132  param.sched_priority = prio;
133  if (0 != (ret = pthread_setschedparam(tid, policy, &param))) {
134  cerr << "[mrpt::system::changeThreadPriority] Warning: Failed call to pthread_setschedparam (error: `" << strerror(ret) << "`)" << endl;
135  return;
136  }
137 #endif
138 }
139 
140 
141 /*---------------------------------------------------------------
142  changeCurrentProcessPriority
143 ---------------------------------------------------------------*/
145 {
146 #ifdef MRPT_OS_WINDOWS
147  DWORD dwPri;
148  switch (priority)
149  {
150  case ppIdle: dwPri = IDLE_PRIORITY_CLASS; break;
151  case ppNormal: dwPri = NORMAL_PRIORITY_CLASS; break;
152  case ppHigh: dwPri = HIGH_PRIORITY_CLASS; break;
153  case ppVeryHigh: dwPri= REALTIME_PRIORITY_CLASS; break;
154  default:
155  THROW_EXCEPTION("Invalid priority value");
156  }
157  SetPriorityClass( GetCurrentProcess(), dwPri );
158 #else
159  int nice_val;
160  switch (priority)
161  {
162  case ppIdle: nice_val =+19; break;
163  case ppNormal: nice_val = 0; break;
164  case ppHigh: nice_val =-10; break;
165  case ppVeryHigh: nice_val =-20; break;
166  default:
167  THROW_EXCEPTION("Invalid priority value");
168  }
169  errno=0;
170  const int ret = nice(nice_val);
171  if (ret==-1 && errno==EPERM) {
172  std::cerr << "[mrpt::system::changeCurrentProcessPriority] Error calling nice(): Not enough permissions.\n";
173  }
174 #endif
175 }
176 
177 /*---------------------------------------------------------------
178  mrpt::system::getCurrentThreadTimes
179 ---------------------------------------------------------------*/
181  time_t &creationTime,
182  time_t &exitTime,
183  double &cpuTime )
184 {
185  MRPT_START
186 
187 #ifdef MRPT_OS_WINDOWS
188  FILETIME timCreat,timExit, timKernel, timUser;
189  uint64_t t;
190 
191  HANDLE threadHandle;
192 
193 #if !defined(HAVE_OPENTHREAD) // defined(_MSC_VER) && (_MSC_VER<1300)
194  // In MSVC6/GCC the ID is just the HANDLE:
195  threadHandle = reinterpret_cast<HANDLE>( mrpt::system::getCurrentThreadId() );
196 #else
197  // Get the handle from the ID:
198  threadHandle = OpenThread( READ_CONTROL | THREAD_QUERY_INFORMATION, FALSE, GetCurrentThreadId() ); // threadId);
199  if (!threadHandle) THROW_EXCEPTION("Cannot open the thread with the given 'threadId'");
200 #endif
201 
202  if (!GetThreadTimes( threadHandle , &timCreat, &timExit, &timKernel, &timUser ))
203  {
204  CloseHandle(threadHandle);
205  THROW_EXCEPTION("Error accessing thread times!");
206  }
207 
208 #if defined(HAVE_OPENTHREAD) // _MSC_VER) && (_MSC_VER>=1300)
209  // From OpenThread...
210  CloseHandle(threadHandle);
211 #endif
212 
213  // Formula is derived from:
214  // http://support.microsoft.com/kb/167296
215  t = (((uint64_t)timCreat.dwHighDateTime) << 32) | timCreat.dwLowDateTime;
216  creationTime = (t - 116444736000000000ULL)/10000000;
217 
218  t = (((uint64_t)timExit.dwHighDateTime) << 32) | timExit.dwLowDateTime;
219  exitTime = (t - 116444736000000000ULL)/10000000;
220 
221  // CPU time is user+kernel:
222  int64_t t1 = (((uint64_t)timKernel.dwHighDateTime) << 32) | timKernel.dwLowDateTime;
223  int64_t t2 = (((uint64_t)timUser.dwHighDateTime) << 32) | timUser.dwLowDateTime;
224 
225  cpuTime = ((double)(t1+t2)) * 100e-9; // FILETIME counts intervals of 100ns
226 
227 #endif
228 
229 #ifdef MRPT_OS_LINUX
230  MRPT_UNUSED_PARAM(creationTime);
231  MRPT_UNUSED_PARAM(exitTime);
232  // Unix:
233 # ifdef HAVE_GETTID
234  pid_t id = gettid();
235 # else
236  // gettid is:
237  // 186 in 64bit
238  // 224 in 32bit
239  #if MRPT_WORD_SIZE==64
240  pid_t id = (long int)syscall(186);
241  #elif MRPT_WORD_SIZE==32
242  pid_t id = (long int)syscall(224);
243  #else
244  #error MRPT_WORD_SIZE must be 32 or 64.
245  #endif
246 # endif
247 
248  // (JL) Refer to: /usr/src/linux/fs/proc/array.c
249  long unsigned tms_utime=0, tms_stime=0;
250  ifstream is(format("/proc/self/task/%i/stat", id).c_str() );
251 
252  if (is.is_open())
253  {
254  string s;
255  getline(is,s);
256 
257  size_t idx = s.find(")");
258 
259  if (idx!=string::npos)
260  {
261  vector_string tokens;
262  mrpt::system::tokenize( string(s.c_str()+idx+1)," ",tokens);
263 
264  if (tokens.size()>=13)
265  {
266  sscanf(tokens[11].c_str(), "%lu" ,&tms_utime);
267  sscanf(tokens[12].c_str(), "%lu", &tms_stime);
268  }
269  }
270  }
271 
272  // Compute cpuTime:
273  double clockTicksPerSecond = (double)sysconf(_SC_CLK_TCK);
274  if (clockTicksPerSecond>0)
275  cpuTime = (tms_utime + tms_stime) / clockTicksPerSecond;
276 #endif
277 
278 #ifdef MRPT_OS_APPLE
279  thread_basic_info info;
280  mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
281  if(thread_info(mach_thread_self(), THREAD_BASIC_INFO, (thread_info_t)&info, &count)==0)
282  {
283  double utime = info.user_time.seconds + info.user_time.microseconds * 1e-6;
284  double stime = info.system_time.seconds + info.system_time.microseconds * 1e-6;
285  cpuTime = utime + stime;
286  }
287 #endif
288 
289  MRPT_END
290 }
291 
292 /*---------------------------------------------------------------
293  launchProcess
294  ---------------------------------------------------------------*/
296 {
297 #ifdef MRPT_OS_WINDOWS
298  STARTUPINFOA SI;
299  PROCESS_INFORMATION PI;
300 
301  memset(&SI,0,sizeof(STARTUPINFOA) );
302  SI.cb = sizeof(STARTUPINFOA);
303 
304  if (CreateProcessA( NULL, (LPSTR)command.c_str(), NULL, NULL, true, 0, NULL, NULL, &SI, &PI) )
305  {
306  // Wait:
307  WaitForSingleObject( PI.hProcess, INFINITE );
308  return true;
309  } // End of process executed OK
310  else
311  {
312  char str[300];
313  DWORD e = GetLastError();
314 
315  FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,0,e,0,str,sizeof(str), NULL);
316 
317  // ERROR:
318  std::cerr << "[launchProcess] Couldn't spawn process. Error msg: " << str << std::endl;
319  return false;
320  }
321 #else
322  return 0== ::system(command.c_str());
323 #endif
324 } // end launchProcess
325 
326 // Return number of processors in the system
328 {
329  static unsigned int ret = 0;
330 
331  if (!ret)
332  {
333 #ifdef MRPT_OS_WINDOWS
334  SYSTEM_INFO si; // Requires Win200 or above.
335  GetSystemInfo(&si);
336  ret=si.dwNumberOfProcessors;
337  if (ret<1) ret=1;
338 #elif defined(MRPT_OS_APPLE)
339  size_t len=sizeof(int);
340  if(sysctlbyname("hw.logicalcpu", &ret, &len, NULL, 0) != 0)
341  ret = 1; // failed
342 #else
343  // This assumes a Linux kernel 2.6
344  ifstream f;
345  f.open("/proc/cpuinfo");
346  if (!f.is_open())
347  return 1; // No info...
348 
349  std::string lin;
350  unsigned int nProc = 0;
351  while (!f.fail() && !f.eof())
352  {
353  std::getline(f,lin);
354  if (!f.fail() && !f.eof())
355  if (lin.find("processor")!=std::string::npos)
356  nProc++;
357  }
358  ret = nProc ? nProc : 1;
359 #endif
360  }
361  return ret;
362 }
363 
364 /*---------------------------------------------------------------
365  exitThread
366  ---------------------------------------------------------------*/
368 {
369 #ifdef MRPT_OS_WINDOWS
370  ExitThread(0);
371 #else
372  pthread_exit(NULL);
373 #endif
374 }
375 
376 /*---------------------------------------------------------------
377  terminateThread
378  ---------------------------------------------------------------*/
380 {
381  if (threadHandle.isClear()) return; // done
382 
383 #ifdef MRPT_OS_WINDOWS
384  TerminateThread(threadHandle.m_thread->native_handle(), DWORD(-1));
385 #elif defined(MRPT_OS_APPLE)
386  pthread_cancel(reinterpret_cast<pthread_t>(threadHandle.m_thread->native_handle()));
387 #else
388  pthread_cancel(threadHandle.m_thread->native_handle());
389 #endif
390  threadHandle.m_thread->join();
391 }
GLuint GLuint GLsizei count
Definition: glext.h:3512
TThreadPriority
The type for cross-platform thread priorities.
Definition: threads.h:61
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:83
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:144
This namespace provides a OS-independent interface to many useful functions: filenames manipulation...
Definition: math_frwds.h:29
#define THROW_EXCEPTION(msg)
unsigned int BASE_IMPEXP getNumberOfProcessors()
Return the number of processors ("cores"), or 1 if it cannot be determined.
Definition: threads.cpp:327
#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:51
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:295
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:180
std::vector< std::string > vector_string
A type for passing a vector of strings.
Definition: types_simple.h:30
#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
GLsizei const GLchar ** string
Definition: glext.h:3919
void BASE_IMPEXP joinThread(TThreadHandle &threadHandle)
Waits until the given thread ends.
Definition: threads.cpp:74
#define MRPT_START
unsigned __int64 uint64_t
Definition: rptypes.h:52
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
std::shared_ptr< std::thread > m_thread
Definition: threads.h:30
backing_store_ptr info
Definition: jmemsys.h:170
A MRPT thread handle.
Definition: threads.h:28
double Tac()
Stops the stopwatch.
Definition: CTicTac.cpp:92
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:379
void BASE_IMPEXP changeCurrentThreadPriority(TThreadPriority priority)
Change the priority of the current thread - for Windows, see also changeCurrentProcessPriority() ...
Definition: threads.cpp:94
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.
void BASE_IMPEXP exitThread() MRPT_NO_THROWS
Explicit close of the current (running) thread.
Definition: threads.cpp:367



Page generated by Doxygen 1.8.14 for MRPT 1.5.7 Git: 5902e14cc Wed Apr 24 15:04:01 2019 +0200 at lun oct 28 01:39:17 CET 2019