User:Kr/A Thread's Life/Example Code
From Apache OpenOffice Wiki
< User:Kr | A Thread's Life(Redirected from User:Kr/A Threads Life/Sample Code)
//
// gcc -Wall -g example.c -o main.bin -lpthread
//
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
void my_pthread_cancel(pthread_t thread) {
int res;
if ((res = pthread_cancel(thread))) {
fprintf(stderr, "%s(%p) => %s\n", __PRETTY_FUNCTION__, (void*)thread, strerror(res));
// There seems to be an issue on Linux with pthread_cancel,
// returning an error in case "thread" has already terminated,
// though not joined.
// abort();
}
}
void my_pthread_join(pthread_t th, void **thread_return) {
int res;
if ((res = pthread_join(th, thread_return))) {
fprintf(stderr, "%s - %s\n", __PRETTY_FUNCTION__, strerror(res));
abort();
}
}
typedef struct Daemon Daemon;
struct Daemon {
Daemon * previous_;
Daemon * next_;
void (*func_)(void);
pthread_t hd_;
int finished_;
};
static pthread_mutex_t daemons_mutex_ = PTHREAD_MUTEX_INITIALIZER;
static Daemon * firstDaemon_ = NULL;
static unsigned int daemons_ = 0;
static void daemons_join_(int finished) {
pthread_mutex_lock(&daemons_mutex_);
Daemon * daemon = firstDaemon_;
while (daemon) {
Daemon * next = daemon->next_;
if (!finished || daemon->finished_) {
-- daemons_;
if (daemon->next_)
daemon->next_->previous_ = daemon->previous_;
if (daemon->previous_)
daemon->previous_->next_ = daemon->next_;
if (firstDaemon_ == daemon)
firstDaemon_ = daemon->next_;
pthread_mutex_unlock(&daemons_mutex_);
my_pthread_join(daemon->hd_, NULL);
pthread_mutex_lock(&daemons_mutex_);
daemon->hd_ = 0xffffffff;
free(daemon);
daemon = firstDaemon_;
}
else
daemon = next;
}
pthread_mutex_unlock(&daemons_mutex_);
}
/* Daemon finish function. */
static void daemon_finish(Daemon * daemon) {
int oldstate;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
daemons_join_(1);
pthread_mutex_lock(&daemons_mutex_);
daemon->finished_ = 1;
pthread_mutex_unlock(&daemons_mutex_);
pthread_setcancelstate(oldstate, NULL);
}
static void * daemon_func(Daemon * daemon) {
pthread_cleanup_push((void (*)(void *))daemon_finish, daemon);
daemon->func_();
pthread_cleanup_pop(1);
return NULL;
}
/* Create a "Daemon" struct and register it.
Start the "Daemon". */
static void daemon_create_(void (*func)(void)) {
Daemon * daemon = malloc(sizeof(Daemon));
daemon->func_ = func;
daemon->finished_ = 0;
pthread_mutex_lock(&daemons_mutex_);
daemon->previous_ = NULL;
daemon->next_ = firstDaemon_;
if (firstDaemon_)
firstDaemon_->previous_ = daemon;
firstDaemon_ = daemon;
++ daemons_;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, 0);
pthread_create(&daemon->hd_, NULL, (void *(*)(void *))daemon_func, daemon);
pthread_attr_destroy(&attr);
pthread_mutex_unlock(&daemons_mutex_);
}
/* Ask all registered daemons for cancellation and join them. */
static void daemons_cancelAndJoin_(void) {
fprintf(stderr, "Joining daemons ... ");
pthread_mutex_lock(&daemons_mutex_);
Daemon * daemon = firstDaemon_;
while (daemon) {
my_pthread_cancel(daemon->hd_);
// respectively
//pthread_kill();
fprintf(stderr, "# ");
daemon = daemon->next_;
}
pthread_mutex_unlock(&daemons_mutex_);
daemons_join_(0);
fprintf(stderr, "done\n");
}
static unsigned int activities_ = 1; // The "main" thread is the first "activity".
static pthread_mutex_t activity_mutex_ = PTHREAD_MUTEX_INITIALIZER;
static void activity_terminate_(void) {
int use_exit = 0;
pthread_mutex_lock(&activity_mutex_);
-- activities_;
use_exit = activities_ == 0;
pthread_mutex_unlock(&activity_mutex_);
// Terminate the process, if this was the last "activity"!
if (use_exit)
exit(0);
else
pthread_exit(NULL);
}
static void * activity_func_(void (*func)(void)) {
func();
activity_terminate_();
return NULL;
}
static void activity_create_(void (*func)(void)) {
pthread_attr_t attr;
/* Activities need to be detached. */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, 1);
pthread_t bt;
pthread_create(&bt, &attr, (void *(*)(void *))activity_func_, func);
pthread_attr_destroy(&attr);
pthread_mutex_lock(&activity_mutex_);
++ activities_;
pthread_mutex_unlock(&activity_mutex_);
}
/* Some daemon functions. */
static void log_threads(void) {
fprintf(stderr, "activities: %u daemons: %u\n", activities_, daemons_);
}
static void log_daemon_(void) {
while (1) {
log_threads();
sleep(1); /* This is a cancellation point. */
}
}
static void some_daemon_(void) {
int n = 10;
while (n) {
sleep(1);
if (rand() < (RAND_MAX / (daemons_ + 1)))
daemon_create_(some_daemon_);
-- n;
}
}
/* Some activity functions. */
static void some_activity_(void) {
int n = 3;
while (n) {
sleep(1);
if (rand() < (RAND_MAX / (activities_ + 1)))
activity_create_(some_activity_);
if (rand() < (RAND_MAX / (daemons_ + 1)))
daemon_create_(some_daemon_);
-- n;
}
}
static void main_activity_(void) {
srand (time (0));
daemon_create_(log_daemon_);
daemon_create_(some_daemon_);
activity_create_(some_activity_);
sleep(3);
daemon_create_(some_daemon_);
sleep(5);
}
int main(void) {
atexit(log_threads);
atexit(daemons_cancelAndJoin_);
main_activity_();
activity_terminate_();
return 0;
}