feisty meow concerns codebase  2.140
thread_cabinet.cpp
Go to the documentation of this file.
1 /*****************************************************************************\
2 * *
3 * Name : thread_cabinet *
4 * Author : Chris Koeritz *
5 * *
6 *******************************************************************************
7 * Copyright (c) 2000-$now By Author. This program is free software; you can *
8 * redistribute it and/or modify it under the terms of the GNU General Public *
9 * License as published by the Free Software Foundation; either version 2 of *
10 * the License or (at your option) any later version. This is online at: *
11 * http://www.fsf.org/copyleft/gpl.html *
12 * Please send any updates to: fred@gruntose.com *
13 \*****************************************************************************/
14 
15 #include "ethread.h"
16 #include "thread_cabinet.h"
17 
19 #include <structures/amorph.h>
20 #include <structures/unique_id.h>
21 #include <timely/time_control.h>
22 
23 #undef LOCKIT
24 #define LOCKIT auto_synchronizer l(*_lock)
25  // grabs the mutex for access to the list.
26 
27 #undef LOG
28 #define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), s)
29 
30 //#define DEBUG_THREAD_CABINET
31  // uncomment for noisier version.
32 
33 using namespace basis;
34 using namespace loggers;
35 using namespace structures;
36 using namespace timely;
37 
38 namespace processes {
39 
40 class thread_record
41 {
42 public:
43  ethread *_thread;
44  unique_int _id;
45 
46  thread_record(const unique_int &id, ethread *t)
47  : _thread(t), _id(id) {}
48 
49  ~thread_record() {
50  _thread->stop();
51  WHACK(_thread);
52  }
53 };
54 
56 
57 class thread_amorph : public amorph<thread_record>
58 {
59 public:
60 };
61 
63 
64 thread_cabinet::thread_cabinet()
65 : _lock(new mutex),
66  _threads(new thread_amorph),
67  _next_id(new int_roller(1, MAXINT32 - 1)),
68  _no_additions(0)
69 {
70 }
71 
73 {
74  WHACK(_threads);
75  WHACK(_lock);
76  WHACK(_next_id);
77 }
78 
79 int thread_cabinet::threads() const { return _threads->elements(); }
80 
82  void *parm)
83 {
84 #ifdef DEBUG_THREAD_CABINET
85  FUNCDEF("add_thread");
86 #endif
87  LOCKIT;
88  if (_no_additions) {
89 #ifdef DEBUG_THREAD_CABINET
90  LOG("no additions flag is true; destroying the thread and failing out.");
91 #endif
92  // can't just leave it unhooked hanging out in space...
93  WHACK(to_add);
94  return 0;
95  }
96  int use_id = _next_id->next_id();
97  if (start_it) {
98  to_add->start(parm);
99  } else {
100 #ifdef DEBUG_THREAD_CABINET
101  if (to_add->thread_finished())
102  LOG(a_sprintf("thread %x is not going to be started and it "
103  "hasn't started yet!", to_add));
104 #endif
105  }
106  _threads->append(new thread_record(use_id, to_add));
107  return use_id;
108 }
109 
111 {
112  LOCKIT;
113  for (int i = 0; i < _threads->elements(); i++) {
114  if (_threads->borrow(i)->_thread->thread_started()) return true;
115  }
116  return false;
117 }
118 
120 {
121  LOCKIT;
122  for (int i = 0; i < _threads->elements(); i++) {
123  if (_threads->borrow(i)->_thread->thread_finished()) {
124  _threads->borrow(i)->_thread->start(ptr);
125  }
126  }
127 }
128 
130 {
131  FUNCDEF("cancel_all");
132  {
133  LOCKIT; // short lock.
134  _no_additions++; // keep people from adding new threads.
135  for (int i = 0; i < _threads->elements(); i++) {
136  _threads->borrow(i)->_thread->cancel();
137  }
138  }
139  LOCKIT;
140  _no_additions--; // allow new threads again.
141  if (_no_additions < 0)
142  continuable_error(class_name(), func, "error in logic regarding "
143  "no additions.");
144 }
145 
147 {
148  FUNCDEF("stop_all");
149  {
150  LOCKIT; // short lock.
151  _no_additions++; // keep people from adding new threads.
152  }
153  cancel_all(); // signal all threads to leave.
154  // pause to give them a little while to leave.
155  time_control::sleep_ms(20);
156  while (true) {
157  LOCKIT; // short lock.
158  if (!_threads->elements()) break; // done; nothing left.
159  clean_debris(); // remove any that did stop.
160  time_control::sleep_ms(20); // snooze for a short while.
161  }
162  LOCKIT;
163  _no_additions--; // allow new threads again.
164  if (_no_additions < 0)
165  continuable_error(class_name(), func, "error in logic regarding "
166  "no additions.");
167 }
168 
170 {
171  LOCKIT;
172  for (int i = 0; i < _threads->elements(); i++) {
173  if (_threads->borrow(i)->_id == to_whack) {
174  // this is the one they want zapped.
175  _threads->zap(i, i);
176  return true;
177  }
178  }
179  return false;
180 }
181 
183 {
184  LOCKIT;
185  for (int i = 0; i < _threads->elements(); i++) {
186  if (_threads->borrow(i)->_id == to_cancel) {
187  // this is the one to signal regarding its own demise.
188  _threads->borrow(i)->_thread->cancel();
189  return true;
190  }
191  }
192  return false;
193 }
194 
196 {
197 #ifdef DEBUG_THREAD_CABINET
198  FUNCDEF("clean_debris");
199 #endif
200  LOCKIT;
201  for (int i = 0; i < _threads->elements(); i++) {
202  if (_threads->borrow(i)->_thread->thread_finished()) {
203  // this one's no longer doing anything.
204 #ifdef DEBUG_THREAD_CABINET
205  LOG(a_sprintf("clearing thread %x out.", _threads->borrow(i)->_thread));
206 #endif
207  _threads->zap(i, i);
208  i--; // skip back before the whack.
209  }
210  }
211 }
212 
214 {
215  LOCKIT;
216  int_set to_return;
217  for (int i = 0; i < _threads->elements(); i++)
218  to_return += _threads->borrow(i)->_id.raw_id();
219  return to_return;
220 }
221 
223 {
224  LOCKIT;
225  thread_record *rec = _threads->borrow(index);
226  if (rec) return rec->_thread;
227  return NULL_POINTER;
228 }
229 
230 } //namespace.
231 
a_sprintf is a specialization of astring that provides printf style support.
Definition: astring.h:440
Provides a platform-independent object for adding threads to a program.
Definition: ethread.h:36
bool start(void *thread_data)
causes the thread to start, if it has not already been started.
Definition: ethread.cpp:146
bool thread_finished() const
returns true if the thread has exited.
Definition: ethread.h:125
bool cancel_thread(const structures::unique_int &to_cancel)
shuts down the thread "to_cancel" as quickly as possible.
bool any_running() const
returns true if any threads are currently running.
bool zap_thread(const structures::unique_int &to_whack)
removes the thread with the id "to_whack".
structures::unique_int add_thread(ethread *to_add, bool start_it, void *parm)
adds a thread to be managed by the thread_cabinet.
void start_all(void *pointer)
cranks up any threads that are not already running.
structures::int_set thread_ids() const
returns the identifiers of all threads managed by this object.
void cancel_all()
signals to all threads that they should exit as soon as possible.
void clean_debris()
clean out threads that have finished.
int threads() const
number of threads being managed here.
ethread * get_thread(int index)
this returns the thread at "index" in our list.
void stop_all()
makes all of the threads quit.
A roller that's based on integers. This is the most common type so far.
Definition: roller.h:79
A simple object that wraps a templated set of ints.
Definition: set.h:156
contents next_id()
returns a unique (per instance of this type) id.
Definition: roller.h:105
A unique identifier based on integers.
Definition: unique_id.h:97
#define continuable_error(c, f, i)
#define NULL_POINTER
The value representing a pointer to nothing.
Definition: definitions.h:32
#define MAXINT32
Maximum 32-bit integer value.
Definition: definitions.h:75
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
Definition: enhance_cpp.h:57
The guards collection helps in testing preconditions and reporting errors.
Definition: array.h:30
void WHACK(contents *&ptr)
deletion with clearing of the pointer.
Definition: functions.h:121
A logger that sends to the console screen using the standard output device.
A dynamic container class that holds any kind of object via pointers.
Definition: amorph.h:55
#include <time.h>
Definition: earth_time.cpp:37
#define LOG(s)
#define LOCKIT