PThread.c++
上传用户:chinafayin
上传日期:2022-04-05
资源大小:153k
文件大小:18k
源码类别:

并行计算

开发平台:

Visual C++

  1. //
  2. // OpenThread library, Copyright (C) 2002 - 2003  The Open Thread Group
  3. //
  4. // This library is free software; you can redistribute it and/or
  5. // modify it under the terms of the GNU Lesser General Public
  6. // License as published by the Free Software Foundation; either
  7. // version 2.1 of the License, or (at your option) any later version.
  8. //
  9. // This library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12. // Lesser General Public License for more details.
  13. // 
  14. // You should have received a copy of the GNU Lesser General Public
  15. // License along with this library; if not, write to the Free Software
  16. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  17. // 
  18. //
  19. // PThread.c++ - C++ Thread class built on top of posix threads.
  20. // ~~~~~~~~~~~
  21. #include <stdlib.h>
  22. #include <stdio.h>
  23. #include <sys/types.h>
  24. #include <unistd.h>
  25. #include <pthread.h>
  26. #include <assert.h>
  27. #if defined __linux || defined __sun || defined __APPLE__
  28. #include <string.h>
  29. #include <sys/time.h>
  30. #include <sys/resource.h>
  31. #include <sys/unistd.h>
  32. #endif
  33. #include "../Thread"
  34. #include "PThreadPrivateData.h"
  35. using namespace OpenThreads;
  36. extern int errno;
  37. const char *OPENTHREAD_VERSION_STRING = "OpenThreads v1.2preAlpha, Posix Threads (Public Implementation)";
  38. #ifdef DEBUG
  39. # define DPRINTF(arg) printf arg
  40. #else
  41. # define DPRINTF(arg)
  42. #endif
  43. //-----------------------------------------------------------------------------
  44. // Initialize the static unique ids.
  45. //
  46. int PThreadPrivateData::nextId = 0;
  47. //-----------------------------------------------------------------------------
  48. // Initialize thread master priority level
  49. //
  50. Thread::ThreadPriority Thread::s_masterThreadPriority =  
  51.                                           Thread::PRIORITY_DEFAULT;
  52. bool Thread::s_isInitialized = false;
  53. pthread_key_t PThreadPrivateData::s_tls_key;
  54. struct ThreadCleanupStruct {
  55.     OpenThreads::Thread *thread;
  56.     volatile bool *runflag;
  57. };
  58. //-----------------------------------------------------------------------------
  59. // This cleanup handler is necessary to ensure that the thread will cleanup
  60. // and set its isRunning flag properly.
  61. //
  62. void thread_cleanup_handler(void *arg) {
  63.     ThreadCleanupStruct *tcs = static_cast<ThreadCleanupStruct *>(arg);
  64.     
  65.     tcs->thread->cancelCleanup();
  66.     *(tcs->runflag) = false;
  67. }
  68. //-----------------------------------------------------------------------------
  69. // Class to support some static methods necessary for pthread's to work
  70. // correctly.
  71. //
  72. namespace OpenThreads {
  73. class ThreadPrivateActions {
  74.     //-------------------------------------------------------------------------
  75.     // We're friendly to Thread, so it can issue the methods.
  76.     //
  77.     friend class Thread;
  78. private:
  79.     //-------------------------------------------------------------------------
  80.     // pthreads standard start routine.
  81.     //
  82.     static void *StartThread(void *data) {
  83. Thread *thread = static_cast<Thread *>(data);
  84. PThreadPrivateData *pd =
  85.     static_cast<PThreadPrivateData *>(thread->_prvData);
  86. ThreadCleanupStruct tcs;
  87. tcs.thread = thread;
  88. tcs.runflag = &pd->isRunning;
  89. // Set local storage so that Thread::CurrentThread() can return the right thing
  90. int status = pthread_setspecific(PThreadPrivateData::s_tls_key, thread);
  91. assert(status == 0);
  92. pthread_cleanup_push(thread_cleanup_handler, &tcs);
  93. #ifdef ALLOW_PRIORITY_SCHEDULING
  94. //---------------------------------------------------------------------
  95. // Set the proper scheduling priorities
  96. //
  97. SetThreadSchedulingParams(thread);
  98. #endif // ] ALLOW_PRIORITY_SCHEDULING
  99.         pd->isRunning = true;
  100.         thread->run();
  101.         pd->isRunning = false;
  102. pthread_cleanup_pop(0);
  103.         return 0;
  104.     };
  105.     //-------------------------------------------------------------------------
  106.     // Print information related to thread schduling parameters.
  107.     //
  108.     static void PrintThreadSchedulingInfo(Thread *thread) {
  109. #ifdef ALLOW_PRIORITY_SCHEDULING // [
  110. if(sysconf(_POSIX_THREAD_PRIORITY_SCHEDULING)) {
  111.     int status, my_policy, min_priority, max_priority;
  112.     struct sched_param my_param;
  113.     
  114.     status = pthread_getschedparam(thread->getProcessId(), 
  115.    &my_policy, 
  116.    &my_param);
  117.     
  118.     if(status != 0) {
  119. printf("THREAD INFO (%d) : Get sched: %sn",
  120.        thread->getProcessId(),
  121.        strerror(status));
  122.     } else {
  123. printf(
  124.     "THREAD INFO (%d) : Thread running at %s / Priority: %dn",
  125.     thread->getProcessId(),
  126.     (my_policy == SCHED_FIFO ? "SCHEDULE_FIFO" 
  127.      : (my_policy == SCHED_RR ? "SCHEDULE_ROUND_ROBIN"
  128. : (my_policy == SCHED_OTHER ? "SCHEDULE_OTHER"
  129.    : "UNKNOWN"))), 
  130.     my_param.sched_priority);
  131. max_priority = sched_get_priority_max(my_policy);
  132. min_priority = sched_get_priority_min(my_policy);
  133. printf(
  134.     "THREAD INFO (%d) : Max priority: %d, Min priority: %dn",
  135.     thread->getProcessId(),
  136.     max_priority, min_priority);
  137.     }
  138.     
  139. } else {
  140.     printf(
  141. "THREAD INFO (%d) POSIX Priority scheduling not availablen",
  142. thread->getProcessId());
  143. }
  144. fflush(stdout);
  145. #endif // ] ALLOW_PRIORITY_SCHEDULING
  146.     
  147.     }
  148.     //--------------------------------------------------------------------------
  149.     // Set thread scheduling parameters.  Unfortunately on Linux, there's no
  150.     // good way to set this, as pthread_setschedparam is mostly a no-op.
  151.     //
  152.     static int SetThreadSchedulingParams(Thread *thread) {
  153. int status = 0;
  154. #ifdef ALLOW_PRIORITY_SCHEDULING // [
  155. if(sysconf(_POSIX_THREAD_PRIORITY_SCHEDULING)) {
  156.     int th_policy; 
  157.     int max_priority, nominal_priority, min_priority;
  158.     sched_param th_param;
  159.     pthread_getschedparam(thread->getProcessId(), 
  160.   &th_policy, &th_param);
  161. #ifndef __linux__
  162.     switch(thread->getSchedulePolicy()) {
  163.     case Thread::SCHEDULE_FIFO:
  164. th_policy = SCHED_FIFO;
  165. break;
  166.     case Thread::SCHEDULE_ROUND_ROBIN:
  167. th_policy = SCHED_RR;
  168. break;
  169.     case Thread::SCHEDULE_TIME_SHARE:
  170. th_policy = SCHED_OTHER;
  171. break;
  172.     default:
  173. #ifdef __sgi
  174. th_policy = SCHED_RR;
  175. #else
  176. th_policy = SCHED_FIFO;
  177. #endif
  178. break;
  179.     };
  180.     
  181. #else
  182.     th_policy = SCHED_OTHER;  // Must protect linux from realtime.
  183. #endif
  184. #ifdef __linux__
  185.     max_priority = 0;
  186.     min_priority = 20;
  187.     nominal_priority = (max_priority + min_priority)/2;
  188. #else
  189.     max_priority = sched_get_priority_max(th_policy);
  190.     min_priority = sched_get_priority_min(th_policy);
  191.     nominal_priority = (max_priority + min_priority)/2;
  192. #endif
  193.     switch(thread->getSchedulePriority()) {
  194.     
  195.     case Thread::PRIORITY_MAX:
  196. th_param.sched_priority = max_priority;
  197. break;
  198.     
  199.     case Thread::PRIORITY_HIGH:
  200. th_param.sched_priority = (max_priority + nominal_priority)/2;
  201. break;
  202.     
  203.     case Thread::PRIORITY_NOMINAL:
  204. th_param.sched_priority = nominal_priority;
  205. break;   
  206.     
  207.     case Thread::PRIORITY_LOW:
  208. th_param.sched_priority = (min_priority + nominal_priority)/2;
  209. break;       
  210.     
  211.     case Thread::PRIORITY_MIN:
  212. th_param.sched_priority = min_priority;
  213. break;   
  214.     
  215.     default:
  216. th_param.sched_priority = max_priority;
  217. break;  
  218.     
  219.     }
  220.      
  221.     status = pthread_setschedparam(thread->getProcessId(), 
  222.    th_policy,
  223.    &th_param);
  224.     if(getenv("OUTPUT_THREADLIB_SCHEDULING_INFO") != 0)
  225. PrintThreadSchedulingInfo(thread);   
  226.     
  227. #endif // ] ALLOW_PRIORITY_SCHEDULING
  228. return status;
  229.     };
  230. };
  231. }
  232. //----------------------------------------------------------------------------
  233. //
  234. // Description: Set the concurrency level (no-op)
  235. //
  236. // Use static public
  237. //
  238. int Thread::SetConcurrency(int concurrencyLevel) {
  239.     
  240. #if defined (__sgi) || defined (__sun)
  241.     return pthread_setconcurrency(concurrencyLevel);
  242. #else
  243.     return -1;
  244. #endif
  245.     
  246. };
  247. //----------------------------------------------------------------------------
  248. //
  249. // Description: Get the concurrency level
  250. //
  251. // Use static public
  252. //
  253. int Thread::GetConcurrency() {
  254. #if defined (__sgi) || defined (__sun)
  255.     return pthread_getconcurrency();
  256. #else
  257.     return -1;
  258. #endif
  259. };
  260. //----------------------------------------------------------------------------
  261. //
  262. // Decription: Constructor
  263. //
  264. // Use: public.
  265. //
  266. Thread::Thread() {
  267.     if(!s_isInitialized) Init();
  268.     PThreadPrivateData *pd = new PThreadPrivateData();
  269.     pd->stackSize = 0;
  270.     pd->stackSizeLocked = false;
  271.     pd->idSet = false;
  272.     pd->isRunning = false;
  273.     pd->isCanceled = false;
  274.     pd->uniqueId = pd->nextId;
  275.     pd->nextId++;
  276.     pd->threadPriority = PRIORITY_DEFAULT;
  277.     pd->threadPolicy = SCHEDULE_DEFAULT;
  278.     _prvData = static_cast<void *>(pd);
  279. }
  280. //----------------------------------------------------------------------------
  281. //
  282. // Decription: Destructor
  283. //
  284. // Use: public.
  285. //
  286. Thread::~Thread() {
  287.     PThreadPrivateData *pd = static_cast<PThreadPrivateData *>(_prvData);
  288.     if(pd->isRunning) {
  289. //---------------------------------------------------------------------
  290. // Kill the thread when it is destructed
  291. //
  292. setCancelModeAsynchronous();
  293. cancel();
  294.     }
  295.     delete pd;
  296. }
  297. Thread *Thread::CurrentThread() {
  298.     
  299.     Thread *thread = 
  300. static_cast<Thread *>(pthread_getspecific(PThreadPrivateData::s_tls_key));
  301.     return thread;
  302. }
  303. //-----------------------------------------------------------------------------
  304. // 
  305. // Description: Initialize Threading
  306. //
  307. // Use: public.
  308. //
  309. void Thread::Init() {
  310.     if(s_isInitialized) return;
  311.     // Allocate a key to be used to access thread local storage
  312.     int status = pthread_key_create(&PThreadPrivateData::s_tls_key, NULL);
  313.     assert(status == 0);
  314. #ifdef ALLOW_PRIORITY_SCHEDULING
  315.     //--------------------------------------------------------------------------
  316.     // If we've got priority scheduling, set things to nominal.
  317.     // 
  318.     if(sysconf(_POSIX_THREAD_PRIORITY_SCHEDULING)) {
  319.        
  320. int max_priority, nominal_priority, min_priority;
  321. int th_policy; 
  322. sched_param th_param;
  323. pthread_getschedparam(pthread_self(), 
  324.       &th_policy, &th_param);
  325. max_priority = sched_get_priority_max(th_policy);
  326. min_priority = sched_get_priority_min(th_policy);
  327. nominal_priority = (max_priority + min_priority)/2;
  328. th_param.sched_priority = nominal_priority;
  329. pthread_setschedparam(pthread_self(), 
  330.       th_policy,
  331.       &th_param);
  332. s_masterThreadPriority = Thread::PRIORITY_NOMINAL;
  333.     } else {
  334. s_masterThreadPriority = Thread::PRIORITY_DEFAULT;
  335.     }
  336. #endif // ] ALLOW_PRIORITY_SCHEDULING
  337.     s_isInitialized = true;
  338. }
  339. //-----------------------------------------------------------------------------
  340. //
  341. // Description: Get a unique identifier for this thread.
  342. //
  343. // Use: public
  344. //
  345. int Thread::getThreadId() {
  346.     PThreadPrivateData *pd = static_cast<PThreadPrivateData *> (_prvData);
  347.     return pd->uniqueId;
  348. }
  349. //-----------------------------------------------------------------------------
  350. //
  351. // Description: Get the thread's process id
  352. //
  353. // Use: public
  354. //
  355. int Thread::getProcessId() {
  356.     
  357.     PThreadPrivateData *pd = static_cast<PThreadPrivateData *> (_prvData);
  358.     if(pd->idSet == false) return (unsigned int) pthread_self();
  359.     
  360.     return (int)(pd->tid);
  361. }
  362. //-----------------------------------------------------------------------------
  363. //
  364. // Description: Determine if the thread is running
  365. //
  366. // Use: public
  367. //
  368. bool Thread::isRunning() {
  369.     PThreadPrivateData *pd = static_cast<PThreadPrivateData *> (_prvData);
  370.     return pd->isRunning;
  371. }
  372. //-----------------------------------------------------------------------------
  373. //
  374. // Description: Start the thread.
  375. //
  376. // Use: public
  377. //
  378. int Thread::start() {
  379.     int status;
  380.     pthread_attr_t thread_attr;
  381.     status = pthread_attr_init( &thread_attr );
  382.     if(status != 0) {
  383. return status;
  384.     }
  385.     PThreadPrivateData *pd = static_cast<PThreadPrivateData *> (_prvData);
  386.     size_t defaultStackSize;
  387.     pthread_attr_getstacksize( &thread_attr, &defaultStackSize);
  388.     if(status != 0) {
  389. return status;
  390.     }
  391.     if(defaultStackSize < pd->stackSize) {
  392. pthread_attr_setstacksize( &thread_attr, pd->stackSize);
  393. if(status != 0) {
  394.     return status;
  395. }
  396.     }
  397.     //-------------------------------------------------------------------------
  398.     // Now get what we actually have...
  399.     //
  400.     pthread_attr_getstacksize( &thread_attr, &defaultStackSize);
  401.     if(status != 0) {
  402. return status;
  403.     }
  404.     pd->stackSize = defaultStackSize;
  405.     //-------------------------------------------------------------------------
  406.     // Prohibit the stack size from being changed.
  407.     //
  408.     pd->stackSizeLocked = true;
  409. #ifdef ALLOW_PRIORITY_SCHEDULING
  410.     status = pthread_attr_setinheritsched( &thread_attr,
  411.    PTHREAD_EXPLICIT_SCHED );
  412.     pthread_attr_setscope(&thread_attr, PTHREAD_SCOPE_SYSTEM);
  413. #endif // ] ALLOW_PRIORITY_SCHEDULING
  414.     if(status != 0) {
  415. return status;
  416.     }
  417.     status = pthread_create(&(pd->tid), &thread_attr,
  418.                            ThreadPrivateActions::StartThread,
  419.                            static_cast<void *>(this));
  420.     if(status != 0) {
  421. return status;
  422.     }
  423.     pd->idSet = true;
  424.     return 0;
  425. }
  426. //-----------------------------------------------------------------------------
  427. //
  428. // Description: Alternate thread start routine.
  429. //
  430. // Use: public
  431. //
  432. int Thread::startThread() { return start(); }
  433. //-----------------------------------------------------------------------------
  434. //
  435. // Description: Join the thread.
  436. //
  437. // Use: public
  438. //
  439. int Thread::detach() {
  440.     PThreadPrivateData *pd = static_cast<PThreadPrivateData *> (_prvData);
  441.     return pthread_detach(pd->tid);
  442. }
  443. //-----------------------------------------------------------------------------
  444. //
  445. // Description: Join the thread.
  446. //
  447. // Use: public
  448. //
  449. int Thread::join() {
  450.     void *threadResult = 0; // Dummy var.
  451.     PThreadPrivateData *pd = static_cast<PThreadPrivateData *> (_prvData);
  452.     return pthread_join(pd->tid, &threadResult);
  453. }
  454. //-----------------------------------------------------------------------------
  455. //
  456. // Description: test the cancel state of the thread.
  457. //
  458. // Use: public
  459. //
  460. int Thread::testCancel() {
  461.     
  462.     PThreadPrivateData *pd = static_cast<PThreadPrivateData *> (_prvData);
  463.     if(pthread_self() != pd->tid)
  464. return -1;
  465.     
  466.     pthread_testcancel();
  467.     return 0;
  468. }
  469. //-----------------------------------------------------------------------------
  470. //
  471. // Description: Cancel the thread.
  472. //
  473. // Use: public
  474. //
  475. int Thread::cancel() {
  476.     PThreadPrivateData *pd = static_cast<PThreadPrivateData *> (_prvData);
  477.     pd->isCanceled = true;
  478.     int status = pthread_cancel(pd->tid);
  479.     return status;
  480. }
  481. //-----------------------------------------------------------------------------
  482. //
  483. // Description: Disable cancelibility
  484. //
  485. // Use: public
  486. //
  487. int Thread::setCancelModeDisable() {
  488.     return pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, 0 );
  489. }
  490. //-----------------------------------------------------------------------------
  491. //
  492. // Description: set the thread to cancel immediately
  493. //
  494. // Use: public
  495. //
  496. int Thread::setCancelModeAsynchronous() {
  497.     int status = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
  498.     if(status != 0) return status;
  499.     return pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, 0);
  500. }
  501. //-----------------------------------------------------------------------------
  502. //
  503. // Description: set the thread to cancel at the next convienent point.
  504. //
  505. // Use: public
  506. //
  507. int Thread::setCancelModeDeferred() {
  508.     int status = pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, 0);
  509.     if(status != 0) return status;
  510.     return pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, 0);
  511. }
  512. //-----------------------------------------------------------------------------
  513. //
  514. // Description: Set the thread's schedule priority (if able)
  515. //
  516. // Use: public
  517. //
  518. int Thread::setSchedulePriority(ThreadPriority priority) {
  519. #ifdef ALLOW_PRIORITY_SCHEDULING
  520.     PThreadPrivateData *pd = static_cast<PThreadPrivateData *> (_prvData);
  521.     
  522.     pd->threadPriority = priority;
  523.     
  524.     if(pd->isRunning) 
  525. return ThreadPrivateActions::SetThreadSchedulingParams(this);
  526.     else 
  527. return 0;
  528. #else
  529.     return -1;
  530. #endif
  531. }
  532. //-----------------------------------------------------------------------------
  533. //
  534. // Description: Get the thread's schedule priority (if able)
  535. //
  536. // Use: public
  537. //
  538. int Thread::getSchedulePriority() {
  539.     PThreadPrivateData *pd = static_cast<PThreadPrivateData *> (_prvData);
  540.     
  541.     return pd->threadPriority;
  542.     
  543. }
  544. //-----------------------------------------------------------------------------
  545. //
  546. // Description: Set the thread's scheduling policy (if able)
  547. //
  548. // Use: public
  549. //
  550. int Thread::setSchedulePolicy(ThreadPolicy policy) {
  551. #ifdef ALLOW_PRIORITY_SCHEDULING
  552.     PThreadPrivateData *pd = static_cast<PThreadPrivateData *> (_prvData);
  553.     
  554.     pd->threadPolicy = policy;
  555.     
  556.     if(pd->isRunning) 
  557. return ThreadPrivateActions::SetThreadSchedulingParams(this);
  558.     else 
  559. return 0;
  560. #else
  561.     return -1;
  562. #endif
  563. }
  564. //-----------------------------------------------------------------------------
  565. //
  566. // Description: Set the thread's scheduling policy (if able)
  567. //
  568. // Use: public
  569. //
  570. int Thread::getSchedulePolicy() {
  571.     PThreadPrivateData *pd = static_cast<PThreadPrivateData *> (_prvData);
  572.     
  573.     return pd->threadPolicy;
  574.     
  575. }
  576. //-----------------------------------------------------------------------------
  577. //
  578. // Description: Set the thread's desired stack size
  579. //
  580. // Use: public
  581. //
  582. int Thread::setStackSize(size_t stackSize) {
  583.     
  584.     PThreadPrivateData *pd = static_cast<PThreadPrivateData *> (_prvData);
  585.     
  586.     if(pd->stackSizeLocked == true) return 13;  // EACESS
  587.     pd->stackSize = stackSize;
  588.     
  589.     return 0;
  590. }
  591. //-----------------------------------------------------------------------------
  592. //
  593. // Description: Get the thread's stack size.
  594. //
  595. // Use: public
  596. //
  597. size_t Thread::getStackSize() {
  598.    PThreadPrivateData *pd = static_cast<PThreadPrivateData *> (_prvData);
  599.     
  600.    return pd->stackSize;
  601. }
  602. //-----------------------------------------------------------------------------
  603. //
  604. // Description:  Print the thread's scheduling information to stdout.
  605. //
  606. // Use: public
  607. //
  608. void Thread::printSchedulingInfo() {
  609.     
  610.     ThreadPrivateActions::PrintThreadSchedulingInfo(this);
  611.     
  612. }
  613. //-----------------------------------------------------------------------------
  614. //
  615. // Description:  Yield the processor
  616. //
  617. // Use: protected
  618. //
  619. int Thread::Yield() {
  620.     return sched_yield();
  621. }