Objectively
Object oriented framework for C.
Loading...
Searching...
No Matches
ThreadPool.c File Reference
#include "Config.h"
#include <assert.h>
#include <stdlib.h>
#include "ThreadPool.h"

Go to the source code of this file.

Data Structures

struct  ThreadPoolWork
 An opaque handle to a ThreadFunction submitted with ThreadPool::execute. More...
 

Macros

#define _Class   _ThreadPool
 

Enumerations

enum  ThreadPoolWorkState { ThreadPoolWorkPending , ThreadPoolWorkRunning , ThreadPoolWorkFinished }
 The states of a ThreadPoolWork. More...
 

Functions

Class * _ThreadPool (void)
 
static ident _wait (ThreadPool *self, ThreadPoolWork *work)
 
static Object * copy (const Object *self)
 
static void dealloc (Object *self)
 
static void dequeue (ThreadPool *self, ThreadPoolWork *work)
 Removes work from the queue.
 
static void detach (ThreadPool *self, ThreadFunction function, ident data)
 
static ThreadPoolWork * execute (ThreadPool *self, ThreadFunction function, ident data)
 
static ThreadPool * init (ThreadPool *self)
 
static void initialize (Class *clazz)
 
static ThreadPool * initWithSize (ThreadPool *self, size_t size)
 
static ident run (Thread *thread)
 ThreadFunction for the ThreadPool Threads.
 
static void runOnCallingThread (ThreadPoolWork *work)
 Runs work on the calling thread, with a Thread that is never started.
 
static ThreadPoolWork * submit (ThreadPool *self, ThreadFunction function, ident data, bool isDetached)
 Queues function, or runs it on the calling thread if this ThreadPool has no Threads.
 

Macro Definition Documentation

◆ _Class

#define _Class   _ThreadPool

Definition at line 39 of file ThreadPool.c.

Enumeration Type Documentation

◆ ThreadPoolWorkState

The states of a ThreadPoolWork.

Enumerator
ThreadPoolWorkPending 
ThreadPoolWorkRunning 
ThreadPoolWorkFinished 

Definition at line 44 of file ThreadPool.c.

44 {
ThreadPoolWorkState
The states of a ThreadPoolWork.
Definition ThreadPool.c:44
@ ThreadPoolWorkPending
Definition ThreadPool.c:45
@ ThreadPoolWorkFinished
Definition ThreadPool.c:47
@ ThreadPoolWorkRunning
Definition ThreadPool.c:46

Function Documentation

◆ _ThreadPool()

Class * _ThreadPool ( void  )

Definition at line 375 of file ThreadPool.c.

375 {
376 static Class *clazz;
377 static Once once;
378
379 do_once(&once, {
380 clazz = _initialize(&(const ClassDef) {
381 .name = "ThreadPool",
382 .superclass = _Object(),
383 .instanceSize = sizeof(ThreadPool),
384 .interfaceSize = sizeof(ThreadPoolInterface),
385 .initialize = initialize,
386 });
387 });
388
389 return clazz;
390}
Class * _initialize(const ClassDef *def)
Initializes the given Class.
Definition Class.c:151
Class * _Object(void)
Definition Object.c:136
static void initialize(Class *clazz)
Definition ThreadPool.c:359
long Once
The Once type.
Definition Once.h:37
#define do_once(once, block)
Executes the given block at most one time.
Definition Once.h:43
ClassDefs are passed to _initialize via an archetype to initialize a Class.
Definition Class.h:41
The runtime representation of a Class.
Definition Class.h:90
A fixed set of Threads that run ThreadFunctions on behalf of the caller.
Definition ThreadPool.h:64

◆ _wait()

static ident _wait ( ThreadPool *  self,
ThreadPoolWork *  work 
)
static

Definition at line 321 of file ThreadPool.c.

321 {
322
323 if (work == NULL) {
324 return NULL;
325 }
326
327 assert(work->pool == self);
328 assert(work->isDetached == false);
329
330 bool isPending = false;
331
332 synchronized(self->condition, {
333 if (work->state == ThreadPoolWorkPending) {
334 dequeue(self, work);
336 isPending = true;
337 } else {
338 while (work->state != ThreadPoolWorkFinished) {
339 $(self->condition, wait);
340 }
341 }
342 });
343
344 if (isPending) {
345 runOnCallingThread(work);
346 }
347
348 const ident result = work->result;
349 free(work);
350
351 return result;
352}
static void dequeue(ThreadPool *self, ThreadPoolWork *work)
Removes work from the queue.
Definition ThreadPool.c:218
static void runOnCallingThread(ThreadPoolWork *work)
Runs work on the calling thread, with a Thread that is never started.
Definition ThreadPool.c:130
void * ident
The identity type, similar to Objective-C id.
Definition Types.h:49
bool isDetached
true if the Thread that runs this ThreadPoolWork frees it.
Definition ThreadPool.c:64
ident result
The return value of the ThreadFunction.
Definition ThreadPool.c:79
ThreadPoolWorkState state
The state.
Definition ThreadPool.c:84
ThreadPool * pool
The ThreadPool owning this work (weak reference).
Definition ThreadPool.c:74

◆ copy()

static Object * copy ( const Object *  self)
static
See also
Object::copy(const Object *)

Definition at line 92 of file ThreadPool.c.

92 {
93 return NULL;
94}

◆ dealloc()

static void dealloc ( Object *  self)
static
See also
Object::dealloc(Object *)

Definition at line 99 of file ThreadPool.c.

99 {
100
101 ThreadPool *this = (ThreadPool *) self;
102
103 const Array *threads = this->threads;
104
105 synchronized(this->condition, {
106 for (size_t i = 0; i < threads->count; i++) {
107 $((Thread *) $(threads, objectAtIndex, i), cancel);
108 }
109 $(this->condition, broadcast);
110 });
111
112 for (size_t i = 0; i < threads->count; i++) {
113 $((Thread *) $(threads, objectAtIndex, i), join, NULL);
114 }
115
116 assert(this->head == NULL);
117
118 release(this->threads);
119
120 release(this->condition);
121
122 super(Object, self, dealloc);
123}
static ident objectAtIndex(const Array *self, size_t index)
Definition Array.c:578
ident release(ident obj)
Atomically decrement the given Object's reference count. If the resulting reference count is 0,...
Definition Class.c:356
#define super(type, obj, method,...)
static void broadcast(Condition *self)
Definition Condition.c:57
static void cancel(Operation *self)
Definition Operation.c:73
static int head(RESTClient *self, const char *url, const char **headers)
Definition RESTClient.c:207
static void join(Thread *self, ident *status)
Definition Thread.c:139
static void dealloc(Object *self)
Definition ThreadPool.c:99
Arrays.
Definition Array.h:56
size_t count
The count of elements.
Definition Array.h:72
Object is the root Class of The Objectively Class hierarchy.
Definition Object.h:46
POSIX Threads.
Definition Thread.h:53

◆ dequeue()

static void dequeue ( ThreadPool *  self,
ThreadPoolWork *  work 
)
static

Removes work from the queue.

Remarks
The caller MUST hold the condition.

Definition at line 218 of file ThreadPool.c.

218 {
219
220 ThreadPoolWork *previous = NULL;
221 for (ThreadPoolWork *w = self->head; w; previous = w, w = w->next) {
222 if (w == work) {
223 if (previous) {
224 previous->next = work->next;
225 } else {
226 self->head = work->next;
227 }
228 if (self->tail == work) {
229 self->tail = previous;
230 }
231 work->next = NULL;
232 return;
233 }
234 }
235
236 assert(false);
237}
An opaque handle to a ThreadFunction submitted with ThreadPool::execute.
Definition ThreadPool.c:50
ThreadPoolWork * next
The next ThreadPoolWork in the queue, or NULL.
Definition ThreadPool.c:69

◆ detach()

static void detach ( ThreadPool *  self,
ThreadFunction  function,
ident  data 
)
static

Definition at line 184 of file ThreadPool.c.

184 {
185 submit(self, function, data, true);
186}
static Data * data(void)
Definition Data.c:286
static ThreadPoolWork * submit(ThreadPool *self, ThreadFunction function, ident data, bool isDetached)
Queues function, or runs it on the calling thread if this ThreadPool has no Threads.
Definition ThreadPool.c:145

◆ execute()

static ThreadPoolWork * execute ( ThreadPool *  self,
ThreadFunction  function,
ident  data 
)
static

Definition at line 192 of file ThreadPool.c.

192 {
193 return submit(self, function, data, false);
194}

◆ init()

static ThreadPool * init ( ThreadPool *  self)
static

Definition at line 200 of file ThreadPool.c.

200 {
201
202#if defined(_WIN32)
203 const size_t size = GetActiveProcessorCount(ALL_PROCESSOR_GROUPS);
204#elif defined(_SC_NPROCESSORS_ONLN)
205 const long processors = sysconf(_SC_NPROCESSORS_ONLN);
206 const size_t size = processors > 0 ? (size_t) processors : 1;
207#else
208 const size_t size = 1;
209#endif
210
211 return $(self, initWithSize, size);
212}
static ThreadPool * initWithSize(ThreadPool *self, size_t size)
Definition ThreadPool.c:290

◆ initialize()

static void initialize ( Class *  clazz)
static
See also
Class::initialize(Class *)

Definition at line 359 of file ThreadPool.c.

359 {
360
361 ((ObjectInterface *) clazz->interface)->copy = copy;
362 ((ObjectInterface *) clazz->interface)->dealloc = dealloc;
363
364 ((ThreadPoolInterface *) clazz->interface)->detach = detach;
365 ((ThreadPoolInterface *) clazz->interface)->execute = execute;
366 ((ThreadPoolInterface *) clazz->interface)->init = init;
367 ((ThreadPoolInterface *) clazz->interface)->initWithSize = initWithSize;
368 ((ThreadPoolInterface *) clazz->interface)->wait = _wait;
369}
static ThreadPoolWork * execute(ThreadPool *self, ThreadFunction function, ident data)
Definition ThreadPool.c:192
static ThreadPool * init(ThreadPool *self)
Definition ThreadPool.c:200
static void detach(ThreadPool *self, ThreadFunction function, ident data)
Definition ThreadPool.c:184
static ident _wait(ThreadPool *self, ThreadPoolWork *work)
Definition ThreadPool.c:321
static Object * copy(const Object *self)
Definition ThreadPool.c:92
ident interface
The interface of the Class.
Definition Class.h:100
void dealloc(Object *self)
Frees all resources held by this Object.
Definition Array.c:99
ident wait(ThreadPool *self, ThreadPoolWork *work)
Waits for the specified ThreadPoolWork to finish, and frees it.
ThreadPool * initWithSize(ThreadPool *self, size_t size)
Initializes this ThreadPool with the specified number of Threads.
Definition ThreadPool.c:290

◆ initWithSize()

static ThreadPool * initWithSize ( ThreadPool *  self,
size_t  size 
)
static

Definition at line 290 of file ThreadPool.c.

290 {
291
292 self = (ThreadPool *) super(Object, self, init);
293 if (self) {
294
295 self->condition = $(alloc(Condition), init);
296 assert(self->condition);
297
298 self->size = size;
299
300 self->threads = $(alloc(Array), initWithCapacity, size);
301 assert(self->threads);
302
303 for (size_t i = 0; i < self->size; i++) {
304 Thread *thread = $(alloc(Thread), initWithFunction, run, self);
305 assert(thread);
306
307 $(self->threads, addObject, thread);
308 $(thread, start);
309
310 release(thread);
311 }
312 }
313
314 return self;
315}
static Array * initWithCapacity(Array *self, size_t capacity)
Definition Array.c:453
static void addObject(Array *self, const ident obj)
Definition Array.c:181
#define alloc(type)
Allocate and initialize and instance of type.
Definition Class.h:226
static Operation * initWithFunction(Operation *self, OperationFunction function, ident data)
Definition Operation.c:125
static void start(Operation *self)
Definition Operation.c:185
static ident run(Thread *thread)
ThreadFunction for the ThreadPool Threads.
Definition ThreadPool.c:244
POSIX Threads conditional variables.
Definition Condition.h:44
size_t size
The number of Threads.
Definition ThreadPool.h:93

◆ run()

static ident run ( Thread *  thread)
static

ThreadFunction for the ThreadPool Threads.

Remarks
thread->data is the user data of the current ThreadPoolWork, so the ThreadPool is kept in a local.

Definition at line 244 of file ThreadPool.c.

244 {
245
246 ThreadPool *self = thread->data;
247 Condition *condition = self->condition;
248
249 $((Lock *) condition, lock);
250
251 while (true) {
252
253 while (self->head == NULL && $(thread, isCancelled) == false) {
254 $(condition, wait);
255 }
256
257 ThreadPoolWork *work = self->head;
258 if (work == NULL) {
259 break;
260 }
261
262 dequeue(self, work);
264
265 $((Lock *) condition, unlock);
266
267 thread->data = work->data;
268 const ident result = work->function(thread);
269
270 $((Lock *) condition, lock);
271
272 if (work->isDetached) {
273 free(work);
274 } else {
275 work->result = result;
277 $(condition, broadcast);
278 }
279 }
280
281 $((Lock *) condition, unlock);
282
283 return NULL;
284}
static void unlock(Lock *self)
Definition Lock.c:103
static void lock(Lock *self)
Definition Lock.c:81
static bool isCancelled(const Operation *self)
Definition Operation.c:140
POSIX Threads locks.
Definition Lock.h:42
ident data
The user data.
Definition Thread.h:69
ident data
The user data.
Definition ThreadPool.c:59
ThreadFunction function
The ThreadFunction.
Definition ThreadPool.c:54

◆ runOnCallingThread()

static void runOnCallingThread ( ThreadPoolWork *  work)
static

Runs work on the calling thread, with a Thread that is never started.

Definition at line 130 of file ThreadPool.c.

130 {
131
132 Thread *thread = $(alloc(Thread), initWithFunction, work->function, work->data);
133 assert(thread);
134
135 work->result = work->function(thread);
137
138 release(thread);
139}

◆ submit()

static ThreadPoolWork * submit ( ThreadPool *  self,
ThreadFunction  function,
ident  data,
bool  isDetached 
)
static

Queues function, or runs it on the calling thread if this ThreadPool has no Threads.

Returns
The ThreadPoolWork, or NULL if isDetached.

Definition at line 145 of file ThreadPool.c.

145 {
146
147 assert(function);
148
149 ThreadPoolWork *work = calloc(1, sizeof(ThreadPoolWork));
150 assert(work);
151
152 work->pool = self;
154 work->isDetached = isDetached;
155 work->function = function;
156 work->data = data;
157
158 if (self->size == 0) {
159 runOnCallingThread(work);
160 if (isDetached) {
161 free(work);
162 return NULL;
163 }
164 return work;
165 }
166
167 synchronized(self->condition, {
168 if (self->tail) {
169 self->tail->next = work;
170 } else {
171 self->head = work;
172 }
173 self->tail = work;
174 $(self->condition, broadcast);
175 });
176
177 return isDetached ? NULL : work;
178}