cpp-pthread  (v1.7.3)
Simple C++ wrapper to pthread functions.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
thread.cpp
1 //
2 // thread.cpp
3 // cpp-pthread
4 //
5 // Created by herbert koelman on 18/03/2016.
6 // Copyright © 2016 urbix-software. All rights reserved.
7 //
8 
9 #include "pthread/thread.hpp"
10 #include <unistd.h>
11 #include <cstdio>
12 
13 namespace pthread {
14 
15  namespace this_thread {
16 
17  void sleep_for(const int millis){
18  usleep(millis * 1000); //NOSONAR this wil be replaced by the much better C++11 implementation std::this_thread::sleep_for
19  }
20 
21  pthread_t get_id(){
22  return pthread_self();
23  }
24  }
25 
26  void thread::join () {
27 
28  if ( _thread != 0){
29 
30  if ( _thread == this_thread::get_id()){
31  throw pthread_exception("join failed, join yourself would endup in deadlock.");
32  }
33 
34  if ( _status == thread_status::not_a_thread ){
35  throw pthread_exception("join failed, this is not a thread.");
36  }
37 
38  int rc = pthread_join(_thread, NULL);
39  if ( rc == 0 ){
40  // thread was successfully joined, it's safe to assume that it's not a thread anymore.
41  _status = thread_status::not_a_thread ;
42  _thread = 0;
43  } else {
44  switch ( rc ) {
45  case EDEADLK:
46  throw thread_exception("EDEADLKpthread_join failed because of deadlock conditions.", rc );
47  case EINVAL:
48  throw thread_exception("EINVEL pthread_join failed not a joinable thread.", rc );
49  case ESRCH:
50  break; // thread has already ended.
51  default:
52  throw thread_exception("pthread_join returned an unexpected return code.", rc);
53  }
54 
55  }
56  }
57  }
58 
59  int thread::cancel () {
60  int rc = 0;
61 
62  if ( _status == thread_status::not_a_thread ){
63  throw pthread_exception("cancel failed, this is not a thread.");
64  }
65 
66  rc = pthread_cancel ( _thread );
67  if(rc != 0){
68  throw thread_exception("pthread_cancel failed.", rc );
69  } else {
71  }
72 
73  return rc;
74  }
75 
76  thread::thread(): _status(thread_status::not_a_thread), _thread(0){
77 
78  // intentional..
79  }
80 
81  thread::thread (const runnable &work, const std::size_t stack_size ): thread(){ // ": thread()" calls the related anonymous constructor
82  int rc = 0 ;
83 
84  /* Initialize and set thread detached attribute */
85  rc = pthread_attr_init(&_attr);
86  if ( rc != 0){
87  throw thread_exception("pthread_attr_init failed.", rc );
88  }
89 
90  rc = pthread_attr_setdetachstate(&_attr, PTHREAD_CREATE_JOINABLE);
91  if ( rc != 0 ){
92  throw thread_exception("pthread_attr_setdetachstate failed.", rc );
93  }
94 
95  rc = pthread_attr_setstacksize(&_attr, stack_size);
96  if ( (stack_size > 0) && (rc != 0) ){
97  throw thread_exception("bad stacksize, check size passed to thread::thread; thread not started.", rc );
98  }
99 
100  rc = pthread_create(&_thread, &_attr, thread_startup_runnable, (void *) &work);
101  if ( rc != 0){
102  throw thread_exception("pthread_create failed.", rc );
103  } else {
104  _status = thread_status::a_thread;
105  }
106 
107  }
108 
109  /* move constructor */
110  thread::thread(thread&& other){ //NOSONAR this a C++11 standard interface that we want to comply with.
111 
112  swap(other);
113  }
114 
116  pthread_attr_destroy(&_attr);
117  }
118 
119  /* move operator */
120  thread& thread::operator=(thread&& other){ //NOSONAR this a C++11 standard interface that we want to comply with.
121 
122  swap(other);
123 
124  return *this;
125  }
126 
127  void thread::swap(thread& other){
128  std::swap(_thread, other._thread);
129  std::swap(_status, other._status);
130  }
131 
132  abstract_thread::abstract_thread(const std::size_t stack_size): _stack_size(stack_size), _thread(NULL){
133  }
134 
135  abstract_thread::~abstract_thread(){
136 
137  if ( _thread != NULL ){
138  delete _thread;
139  }
140  }
141 
143 
144  _thread = new pthread::thread(*this, _stack_size);
145  }
146 
148  _thread->join() ;
149  };
150 
152  return _thread != 0 ;
153  };
154 
155 #if __cplusplus < 201103L
156  thread_group::thread_group(bool destructor_joins_first) throw(): _destructor_joins_first(destructor_joins_first){
157 #else
158  thread_group::thread_group(bool destructor_joins_first) noexcept: _destructor_joins_first(destructor_joins_first){
159 #endif
160 
161  }
162 
164 
165  while(! _threads.empty()){
166 
167 #if __cplusplus < 201103L
168  std::auto_ptr<pthread::abstract_thread> pat(_threads.front());
169 #else
170  std::unique_ptr<pthread::abstract_thread> pat(_threads.front());
171 #endif
172 
173  _threads.pop_front();
174 
175  if ( _destructor_joins_first && pat->joinable() ){
176  try {
177  pat->join();
178  } catch ( pthread_exception &err ){
179  printf("thread_group destructor failed to join one thread. %s, (%d) %s.\n", err.what(), err.pthread_errno(), err.pthread_errmsg());
180  } catch ( ... ){ //NOSONAR this was done on purpose to avoid crashes due to unhandled error conditions. This should never happen.
181  printf("thread_group destructor received an unexpected exception when joining threads.");
182  };
183  }
184  }
185  }
186 
188 
189  _threads.push_back(thread);
190  }
191 
193  for(auto iterator = _threads.begin(); iterator != _threads.end(); iterator++){
194  (*iterator)->start();
195  }
196  }
197 
199  for(auto iterator = _threads.begin(); iterator != _threads.end(); iterator++){
200  if ( (*iterator)->joinable() ){
201  (*iterator)->join();
202  }
203  }
204  }
205 
206  unsigned long thread_group::size(){
207  return _threads.size();
208  }
209 
215  void *thread_startup_runnable(void *runner) {
216 
217  try{
218  static_cast<runnable *>(runner)->run();
219  } catch ( ... ) { // NOSONAR threads cannot throw exceptions when ending, this prevents this from happening.
220  printf("uncaugth excpetion in thread_startup_runnable(), check your runnable::run() implementation.");
221  }
222  return NULL ;
223  }
224 
225 } // namespace pthread
bool joinable() const
Definition: thread.cpp:151
virtual ~thread()
Definition: thread.cpp:115
void sleep_for(const int millis)
Definition: thread.cpp:17
virtual int pthread_errno()
Definition: exceptions.cpp:32
virtual const char * what() const noexceptoverride
Definition: exceptions.cpp:27
void add(abstract_thread *thread)
Definition: thread.cpp:187
void * thread_startup_runnable(void *)
Definition: thread.cpp:215
thread_status
Definition: thread.hpp:47
virtual ~thread_group()
Definition: thread.cpp:163
thread_group(bool destructor_joins_first=false) noexcept
Definition: thread.cpp:158
pthread_t get_id()
Definition: thread.cpp:21
void join()
Definition: thread.cpp:26
int cancel()
Definition: thread.cpp:59
abstract_thread(const std::size_t stack_size=0)
Definition: thread.cpp:132
thread & operator=(const thread &)=delete
unsigned long size()
Definition: thread.cpp:206
virtual const char * pthread_errmsg()
Definition: exceptions.cpp:36