Skip to content

Instantly share code, notes, and snippets.

@ELLIOTTCABLE
Created May 5, 2010 07:42
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ELLIOTTCABLE/390498 to your computer and use it in GitHub Desktop.
Save ELLIOTTCABLE/390498 to your computer and use it in GitHub Desktop.
thread Thread__create(pool a_pool) {
thread this = malloc(sizeof(struct thread));
this->pthread = malloc(sizeof(pthread_t));
this->pool = a_pool;
pthread_create(&this->pthread,
NULL, (void *(*)(void *))register_a_thread, (void *)this);
return this;
}
void register_a_thread(void *argument) {
thread this = (thread)argument;
this->initialized = true;
Thread.work(this);
Thread.destroy(this);
//return; /* This can never return; `Thread.destroy()` calls `pthread_exit()`. */
}
void thread__work(thread this) {
/* This is the primary work loop. As long as the thread is `initialized`
* (meaning it hasn’t been informed that it should terminate), it will
* wait for signals (via it’s pool’s condvar) that there is work available
* to be done, specifically, that there are routines in the queue to be
* interpreted.
* --
* FIXME: Should we move the *loop* out of here, and just have the condition
* check? Perhaps move even that out, and only execute routines. */
while (this->initialized) {
pthread_mutex_lock ( this->pool->mutex);
pthread_cond_wait (this->pool->condition, this->pool->mutex);
pthread_mutex_unlock( this->pool->mutex);
/* Once the thread is woken up by a condvar signal, we check that there’s
* actually routines to process (if not, it falls through to waiting
* again) */
while (this->initialized && this->pool->size > 0)
Paws.Routine.execute( Pool.drip(this->pool) );
}
/* Usually, this is called from `register_a_thread()`, so it’s quite likely
* that the thread will destroy itself after this returns. */
return;
}
void thread__destroy(thread this) {
this->initialized = false;
/* If `this` is the current thread, we directly kill ourselves after having
* cleaned up. Else, we `join` against the passed `thread`, blocking until
* it finishes its work and terminates. */
if (pthread_equal( pthread_self(), this->pthread )) {
/* FIXME: How do I deallocate the `pthread_t` structure? There’s no
* documented `pthread_destroy()` function. */
/* FIXME: How do I ensure nobody else tries to access this after it is
* freed? Other people may still have references to it. */
free(this);
pthread_exit(NULL);
} else {
/* TODO: Find a way to signal a specific thread to wake, instead of
* broadcasting a pointless wake to *all* threads in the pool. Seems
* wasteful, if not dangerous. */
pthread_cond_broadcast(this->pool->condition);
/* TODO: Replace this with an ‘is active’ mutex; prevent any destructive
* modifications to the `thread` structure while it’s running.
* Locking against that mutex would be equivalent to `join`ing,
* because the thread would only release the mutex while it’s
* shutting down. */
pthread_join(this->pthread, NULL);
free(this);
}
return; /* This will never return, if called from the thread itself */
}
pool Pool__create(void) {
pool this = malloc(sizeof( struct pool ));
this->mutex = malloc(sizeof( pthread_mutex_t ));
this->condition = malloc(sizeof( pthread_cond_t ));
this->size = 0;
this->queue = NULL;
/* We initialize the mutex, and just to be safe, lock against it. */
pthread_mutex_init (this->mutex, NULL);
pthread_mutex_lock (this->mutex);
pthread_cond_init (this->condition, NULL);
pthread_mutex_unlock(this->mutex);
return this;
}
void pool__enqueue(pool this, routine a_routine) {
routine *queue = malloc(sizeof(routine) * this->size + 1);
memcpy(queue, this->queue, sizeof(routine) * this->size);
queue[this->size] = a_routine;
this->queue = queue;
this->size++;
pthread_cond_signal (this->condition);
}
routine pool__drip(pool this) {
routine first = this->queue[0];
routine *queue = malloc(sizeof(routine) * this->size - 1);
memcpy(queue, this->queue + 1, sizeof(routine) * this->size - 1);
this->queue = queue;
this->size--;
return first;
}
void pool__destroy(pool this) {
/* TODO: Clean up. */
free(this);
return;
}
@abbytabbyvriel
Copy link

ees very pretty.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment