Difference between revisions of "User:Kr/A Thread's Life/Library Example"
(Library Example) |
m (.) |
||
Line 1: | Line 1: | ||
+ | ===The Main Program=== | ||
<code>[cpp] | <code>[cpp] | ||
− | / | + | /* |
− | + | ** gcc -Wall -g main.c -o main.bin -lpthread -ldl | |
− | / | + | */ |
+ | #include "library.h" | ||
+ | |||
#include <stdlib.h> | #include <stdlib.h> | ||
#include <stdio.h> | #include <stdio.h> | ||
Line 11: | Line 14: | ||
− | static unsigned int activities_ = 1; / | + | static unsigned int activities_ = 1; /* The "main" thread is the first "activity". */ |
static pthread_mutex_t activity_mutex_ = PTHREAD_MUTEX_INITIALIZER; | static pthread_mutex_t activity_mutex_ = PTHREAD_MUTEX_INITIALIZER; | ||
Line 21: | Line 24: | ||
pthread_mutex_unlock(&activity_mutex_); | pthread_mutex_unlock(&activity_mutex_); | ||
− | / | + | /* Terminate the process, if this was the last "activity"! */ |
if (use_exit) | if (use_exit) | ||
exit(0); | exit(0); | ||
Line 55: | Line 58: | ||
/* Some daemon functions. */ | /* Some daemon functions. */ | ||
− | static | + | static daemon_create_t * pdaemon_create_; |
− | + | static daemons_getCount_t * pdaemons_getCount_; | |
− | static | + | |
− | + | ||
Line 69: | Line 70: | ||
log_threads(); | log_threads(); | ||
− | + | /* This is a cancellation point. */ | |
+ | sleep(1); | ||
} | } | ||
} | } | ||
Line 102: | Line 104: | ||
static void main_activity_(void) { | static void main_activity_(void) { | ||
− | srand (time (0)); | + | srand(time (0)); |
pdaemon_create_(log_daemon_); | pdaemon_create_(log_daemon_); | ||
Line 117: | Line 119: | ||
static void close_library(void) { | static void close_library(void) { | ||
− | + | daemons_cancelAndJoin_t * pdaemons_cancelAndJoin = dlsym(dlhd_, "daemons_cancelAndJoin"); | |
if (pdaemons_cancelAndJoin) pdaemons_cancelAndJoin(); | if (pdaemons_cancelAndJoin) pdaemons_cancelAndJoin(); | ||
dlclose(dlhd_); | dlclose(dlhd_); | ||
Line 129: | Line 131: | ||
dlhd_ = dlopen("library.so", RTLD_NOW); | dlhd_ = dlopen("library.so", RTLD_NOW); | ||
− | pdaemon_create_ = dlsym(dlhd_, "daemon_create"); | + | pdaemon_create_ = dlsym(dlhd_, "daemon_create"); |
pdaemons_getCount_ = dlsym(dlhd_, "daemons_getCount"); | pdaemons_getCount_ = dlsym(dlhd_, "daemons_getCount"); | ||
Line 140: | Line 142: | ||
</code> | </code> | ||
+ | ===Library Header=== | ||
<code>[cpp] | <code>[cpp] | ||
− | / | + | #ifndef library_h_included |
− | / | + | # define library_h_included |
− | / | + | |
+ | |||
+ | typedef void daemon_create_t (void (*func)(void)); | ||
+ | typedef int daemons_getCount_t (void); | ||
+ | typedef void daemons_cancelAndJoin_t(void); | ||
+ | |||
+ | |||
+ | void daemon_create (void (*func)(void)); | ||
+ | int daemons_getCount (void); | ||
+ | void daemons_cancelAndJoin(void); | ||
+ | |||
+ | |||
+ | #endif | ||
+ | </code> | ||
+ | |||
+ | ===Library Implementation=== | ||
+ | <code>[cpp] | ||
+ | /* | ||
+ | ** gcc -Wall -g library.c -shared -o library.so -lpthread | ||
+ | */ | ||
+ | #include "library.h" | ||
#include <stdlib.h> | #include <stdlib.h> | ||
Line 156: | Line 179: | ||
if ((res = pthread_cancel(thread))) { | if ((res = pthread_cancel(thread))) { | ||
fprintf(stderr, "%s(%p) => %s\n", __PRETTY_FUNCTION__, (void*)thread, strerror(res)); | 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(); */ |
} | } | ||
} | } | ||
Line 191: | Line 214: | ||
} | } | ||
+ | /* Joins all or only "finished" daemons. */ | ||
static void daemons_join_(int finished) { | static void daemons_join_(int finished) { | ||
pthread_mutex_lock(&daemons_mutex_); | pthread_mutex_lock(&daemons_mutex_); | ||
Line 226: | Line 250: | ||
/* Daemon finish function. */ | /* Daemon finish function. */ | ||
− | static void | + | static void daemon_finish_(Daemon * daemon) { |
int oldstate; | int oldstate; | ||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); | pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); | ||
Line 239: | Line 263: | ||
} | } | ||
− | static void * | + | static void * daemon_func_(Daemon * daemon) { |
− | pthread_cleanup_push((void (*)(void *)) | + | pthread_cleanup_push((void (*)(void *))daemon_finish_, daemon); |
− | + | ||
daemon->func_(); | daemon->func_(); | ||
− | |||
pthread_cleanup_pop(1); | pthread_cleanup_pop(1); | ||
Line 249: | Line 271: | ||
} | } | ||
− | /* Create a "Daemon" struct and register it. | + | /* Create a "Daemon" struct and register it. Start the "Daemon". */ |
− | + | ||
void daemon_create(void (*func)(void)) { | void daemon_create(void (*func)(void)) { | ||
Daemon * daemon = malloc(sizeof(Daemon)); | Daemon * daemon = malloc(sizeof(Daemon)); | ||
Line 270: | Line 291: | ||
pthread_attr_init(&attr); | pthread_attr_init(&attr); | ||
pthread_attr_setdetachstate(&attr, 0); | pthread_attr_setdetachstate(&attr, 0); | ||
− | pthread_create(&daemon->hd_, NULL, (void *(*)(void *)) | + | pthread_create(&daemon->hd_, NULL, (void *(*)(void *))daemon_func_, daemon); |
pthread_attr_destroy(&attr); | pthread_attr_destroy(&attr); | ||
Line 277: | Line 298: | ||
/* Ask all registered daemons for cancellation and join them. */ | /* Ask all registered daemons for cancellation and join them. */ | ||
− | / | + | /* Calling pthread_canel from within _fini leads to deadlocks.*/ |
− | // static void __attribute__((destructor)) daemons_cancelAndJoin_(void) { | + | /* static void __attribute__((destructor)) daemons_cancelAndJoin_(void) {*/ |
void daemons_cancelAndJoin(void) { | void daemons_cancelAndJoin(void) { | ||
Line 287: | Line 308: | ||
while (daemon) { | while (daemon) { | ||
my_pthread_cancel(daemon->hd_); | my_pthread_cancel(daemon->hd_); | ||
− | / | + | /* respectively */ |
− | / | + | /*pthread_kill();*/ |
fprintf(stderr, "# "); | fprintf(stderr, "# "); | ||
Line 296: | Line 317: | ||
pthread_mutex_unlock(&daemons_mutex_); | pthread_mutex_unlock(&daemons_mutex_); | ||
fprintf(stderr, "done\n"); | fprintf(stderr, "done\n"); | ||
+ | |||
fprintf(stderr, "Joining daemons ... "); | fprintf(stderr, "Joining daemons ... "); |
Revision as of 07:54, 2 October 2007
The Main Program
[cpp]
/*
- gcc -Wall -g main.c -o main.bin -lpthread -ldl
- /
- include "library.h"
- include <stdlib.h>
- include <stdio.h>
- include <pthread.h>
- include <string.h>
- include <unistd.h>
- include <dlfcn.h>
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 daemon_create_t * pdaemon_create_;
static daemons_getCount_t * pdaemons_getCount_;
static void log_threads(void) {
fprintf(stderr, "activities: %u daemons: %u\n", activities_, pdaemons_getCount_ ? pdaemons_getCount_() : 0);
}
static void log_daemon_(void) {
while (1) { log_threads();
/* This is a cancellation point. */ sleep(1); }
}
static void some_daemon_(void) {
int n = 10; while (n) { sleep(1); if (rand() < (RAND_MAX / (pdaemons_getCount_() + 1))) pdaemon_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 / (pdaemons_getCount_() + 1))) pdaemon_create_(some_daemon_);
-- n; }
}
static void main_activity_(void) {
srand(time (0));
pdaemon_create_(log_daemon_); pdaemon_create_(some_daemon_); activity_create_(some_activity_); sleep(3); pdaemon_create_(some_daemon_);
sleep(5);
}
static void * dlhd_ = NULL;
static void close_library(void) {
daemons_cancelAndJoin_t * pdaemons_cancelAndJoin = dlsym(dlhd_, "daemons_cancelAndJoin"); if (pdaemons_cancelAndJoin) pdaemons_cancelAndJoin(); dlclose(dlhd_); pdaemon_create_ = NULL; pdaemons_getCount_ = NULL;
}
int main(void) {
atexit(log_threads); atexit(close_library);
dlhd_ = dlopen("library.so", RTLD_NOW); pdaemon_create_ = dlsym(dlhd_, "daemon_create"); pdaemons_getCount_ = dlsym(dlhd_, "daemons_getCount");
main_activity_();
activity_terminate_();
return 0;
}
Library Header
[cpp]
- ifndef library_h_included
- define library_h_included
typedef void daemon_create_t (void (*func)(void));
typedef int daemons_getCount_t (void);
typedef void daemons_cancelAndJoin_t(void);
void daemon_create (void (*func)(void));
int daemons_getCount (void);
void daemons_cancelAndJoin(void);
- endif
Library Implementation
[cpp]
/*
- gcc -Wall -g library.c -shared -o library.so -lpthread
- /
- include "library.h"
- include <stdlib.h>
- include <stdio.h>
- include <pthread.h>
- include <string.h>
- include <unistd.h>
static 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(); */
}
}
static 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;
int daemons_getCount(void) {
return daemons_;
}
/* Joins all or only "finished" daemons. */ 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". */ 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. */ /* Calling pthread_canel from within _fini leads to deadlocks.*/ /* static void __attribute__((destructor)) daemons_cancelAndJoin_(void) {*/
void daemons_cancelAndJoin(void) {
fprintf(stderr, "Cancelling 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_); fprintf(stderr, "done\n");
fprintf(stderr, "Joining daemons ... "); daemons_join_(0); fprintf(stderr, "done\n");
}