Difference between revisions of "User:Kr/A Thread's Life/Example Code"
m (Now creates randomly activities and daemons ...) |
m (Worked in some code review comments, improved structure.) |
||
Line 16: | Line 16: | ||
Daemon * next_; | Daemon * next_; | ||
+ | void (*func_)(void); | ||
pthread_t hd_; | pthread_t hd_; | ||
}; | }; | ||
Line 23: | Line 24: | ||
static pthread_mutex_t daemons_mutex_ = PTHREAD_MUTEX_INITIALIZER; | static pthread_mutex_t daemons_mutex_ = PTHREAD_MUTEX_INITIALIZER; | ||
− | + | /* Unregister the given "Daemon" struct | |
− | + | and terminate this thread. */ | |
− | + | static void daemon_terminate(Daemon * daemon) { | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | static void | + | |
− | + | ||
− | + | ||
pthread_mutex_lock(&daemons_mutex_); | pthread_mutex_lock(&daemons_mutex_); | ||
-- daemons_; | -- daemons_; | ||
Line 62: | Line 43: | ||
free(daemon); | free(daemon); | ||
− | / | + | /* This daemon is not in the list of daemons anymore, |
− | + | and therefor can't be joined. */ | |
pthread_detach(pthread_self()); | pthread_detach(pthread_self()); | ||
} | } | ||
− | static void | + | static void * daemon_func(Daemon * daemon) { |
+ | pthread_cleanup_push((void (*)(void *))daemon_terminate, daemon); | ||
− | + | daemon->func_(); | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
pthread_cleanup_pop(1); | pthread_cleanup_pop(1); | ||
Line 87: | Line 58: | ||
} | } | ||
− | static void | + | /* Create a "Daemon" struct and register it. |
− | fprintf(stderr, " | + | Start the "Daemon". */ |
+ | static void daemon_create_(void (*func)(void)) { | ||
+ | Daemon * daemon = malloc(sizeof(Daemon)); | ||
+ | daemon->func_ = func; | ||
+ | |||
+ | pthread_mutex_lock(&daemons_mutex_); | ||
+ | |||
+ | daemon->previous_ = NULL; | ||
+ | daemon->next_ = firstDaemon_; | ||
+ | |||
+ | if (firstDaemon_) | ||
+ | firstDaemon_->previous_ = daemon; | ||
+ | |||
+ | firstDaemon_ = daemon; | ||
+ | ++ daemons_; | ||
+ | |||
+ | pthread_mutex_unlock(&daemons_mutex_); | ||
+ | |||
+ | |||
+ | pthread_create(&daemon->hd_, NULL, (void *(*)(void *))daemon_func, daemon); | ||
+ | } | ||
+ | |||
+ | /* Ask all registered daemons for termination and join them. */ | ||
+ | static void daemons_join_(void) { | ||
+ | fprintf(stderr, "Joining daemons ... "); | ||
pthread_mutex_lock(&daemons_mutex_); | pthread_mutex_lock(&daemons_mutex_); | ||
while (firstDaemon_) { | while (firstDaemon_) { | ||
pthread_t hd; | pthread_t hd; | ||
− | |||
memcpy(&hd, &firstDaemon_->hd_, sizeof(pthread_t)); | memcpy(&hd, &firstDaemon_->hd_, sizeof(pthread_t)); | ||
Line 104: | Line 98: | ||
pthread_join(hd, NULL); | pthread_join(hd, NULL); | ||
+ | fprintf(stderr, "# "); | ||
pthread_mutex_lock(&daemons_mutex_); | pthread_mutex_lock(&daemons_mutex_); | ||
Line 110: | Line 105: | ||
fprintf(stderr, "done\n"); | fprintf(stderr, "done\n"); | ||
− | |||
− | |||
− | |||
− | |||
− | |||
} | } | ||
Line 121: | Line 111: | ||
static pthread_mutex_t activity_mutex_ = PTHREAD_MUTEX_INITIALIZER; | static pthread_mutex_t activity_mutex_ = PTHREAD_MUTEX_INITIALIZER; | ||
− | static void | + | static void activity_terminate_(void) { |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
int use_exit = 0; | int use_exit = 0; | ||
pthread_mutex_lock(&activity_mutex_); | pthread_mutex_lock(&activity_mutex_); | ||
Line 142: | Line 126: | ||
} | } | ||
− | static void | + | static void * activity_func_(void (*func)(void)) { |
+ | func(); | ||
− | + | activity_terminate_(); | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | return NULL; | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
} | } | ||
− | static void | + | static void activity_create_(void (*func)(void)) { |
pthread_attr_t attr; | pthread_attr_t attr; | ||
+ | /* Activities need to be detached. */ | ||
pthread_attr_init(&attr); | pthread_attr_init(&attr); | ||
pthread_attr_setdetachstate(&attr, 1); | pthread_attr_setdetachstate(&attr, 1); | ||
pthread_t bt; | pthread_t bt; | ||
− | pthread_create(&bt, &attr, | + | pthread_create(&bt, &attr, (void *(*)(void *))activity_func_, func); |
pthread_attr_destroy(&attr); | pthread_attr_destroy(&attr); | ||
− | + | pthread_mutex_lock(&activity_mutex_); | |
+ | ++ activities_; | ||
+ | pthread_mutex_unlock(&activity_mutex_); | ||
} | } | ||
− | static void | + | /* Some daemon functions. */ |
+ | static void log_threads(void) { | ||
+ | fprintf(stderr, "activities: %u daemons: %u\n", activities_, daemons_); | ||
+ | } | ||
+ | |||
+ | static void log_daemon_(void) { | ||
while (1) { | while (1) { | ||
− | + | log_threads(); | |
− | sleep(1); | + | sleep(1); /* This is a cancellation point. */ |
} | } | ||
Line 185: | Line 166: | ||
} | } | ||
+ | static void some_daemon_(void) { | ||
+ | int n = 10; | ||
+ | while (n) { | ||
+ | sleep(1); | ||
+ | |||
+ | if (rand() < (RAND_MAX / (daemons_ + 1))) | ||
+ | daemon_create_(some_daemon_); | ||
− | + | -- n; | |
+ | } | ||
+ | } | ||
− | static void | + | /* 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 | + | 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) { | int main(void) { | ||
− | + | atexit(log_threads); | |
+ | atexit(daemons_join_); | ||
− | + | main_activity_(); | |
− | + | ||
− | + | activity_terminate_(); | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
return 0; | return 0; | ||
} | } | ||
</code> | </code> |
Revision as of 09:45, 6 September 2007
[cpp]
//
// gcc -g main.c -o main.bin -lpthread
//
- include <stdlib.h>
- include <stdio.h>
- include <pthread.h>
- include <string.h>
typedef struct Daemon Daemon;
struct Daemon {
Daemon * previous_; Daemon * next_;
void (*func_)(void); pthread_t hd_;
};
static Daemon * firstDaemon_ = NULL; static unsigned int daemons_ = 0; static pthread_mutex_t daemons_mutex_ = PTHREAD_MUTEX_INITIALIZER;
/* Unregister the given "Daemon" struct
and terminate this thread. */
static void daemon_terminate(Daemon * daemon) {
pthread_mutex_lock(&daemons_mutex_); -- 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_);
free(daemon);
/* This daemon is not in the list of daemons anymore, and therefor can't be joined. */ pthread_detach(pthread_self());
}
static void * daemon_func(Daemon * daemon) {
pthread_cleanup_push((void (*)(void *))daemon_terminate, 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;
pthread_mutex_lock(&daemons_mutex_);
daemon->previous_ = NULL; daemon->next_ = firstDaemon_;
if (firstDaemon_) firstDaemon_->previous_ = daemon;
firstDaemon_ = daemon; ++ daemons_;
pthread_mutex_unlock(&daemons_mutex_);
pthread_create(&daemon->hd_, NULL, (void *(*)(void *))daemon_func, daemon);
}
/* Ask all registered daemons for termination and join them. */ static void daemons_join_(void) {
fprintf(stderr, "Joining daemons ... ");
pthread_mutex_lock(&daemons_mutex_); while (firstDaemon_) { pthread_t hd; memcpy(&hd, &firstDaemon_->hd_, sizeof(pthread_t));
pthread_mutex_unlock(&daemons_mutex_);
// We may want to cancel a thread actively during termination: pthread_cancel(hd); // respectively //pthread_kill();
pthread_join(hd, NULL); fprintf(stderr, "# ");
pthread_mutex_lock(&daemons_mutex_); } pthread_mutex_unlock(&daemons_mutex_);
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. */ }
pthread_exit(NULL);
}
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_join_);
main_activity_();
activity_terminate_();
return 0;
}