Difference between revisions of "User:Kr/A Thread's Life/Example Code"

From Apache OpenOffice Wiki
Jump to: navigation, search
m (Worked in some code review comments, improved structure.)
m (Fixed a race - should always do proper error handling to actually see the problems ;-))
Line 1: Line 1:
 
<code>[cpp]
 
<code>[cpp]
 
//
 
//
// gcc -g main.c -o main.bin -lpthread
+
// gcc -g example.c -o main.bin -lpthread
 
//  
 
//  
  
Line 8: Line 8:
 
#include <pthread.h>
 
#include <pthread.h>
 
#include <string.h>
 
#include <string.h>
 +
 +
 +
void my_pthread_cancel(pthread_t thread) {
 +
    int res;
 +
    if (res = pthread_cancel(thread)) {
 +
        fprintf(stderr, "%s - %s\n", __PRETTY_FUNCTION__, strerror(res));
 +
        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();
 +
    }
 +
}
  
  
Line 18: Line 35:
 
     void (*func_)(void);
 
     void (*func_)(void);
 
     pthread_t hd_;
 
     pthread_t hd_;
 +
    int      inJoin_;
 
};
 
};
  
 +
static pthread_mutex_t daemons_mutex_ = PTHREAD_MUTEX_INITIALIZER;
 
static Daemon        * firstDaemon_  = NULL;
 
static Daemon        * firstDaemon_  = NULL;
 
static unsigned    int daemons_      = 0;  
 
static unsigned    int daemons_      = 0;  
static pthread_mutex_t daemons_mutex_ = PTHREAD_MUTEX_INITIALIZER;
 
  
 
/* Unregister the given "Daemon" struct
 
/* Unregister the given "Daemon" struct
Line 38: Line 56:
 
     if (firstDaemon_ == daemon)
 
     if (firstDaemon_ == daemon)
 
         firstDaemon_ = daemon->next_;
 
         firstDaemon_ = daemon->next_;
 +
 +
 +
    /* This daemon is not in the list of daemons anymore,
 +
      and therefor can't be joined, except if acively cancelled. */
 +
    if (!daemon->inJoin_)
 +
        pthread_detach(pthread_self());
  
 
     pthread_mutex_unlock(&daemons_mutex_);
 
     pthread_mutex_unlock(&daemons_mutex_);
Line 43: Line 67:
 
     free(daemon);
 
     free(daemon);
  
    /* This daemon is not in the list of daemons anymore,
 
      and therefor can't be joined. */
 
    pthread_detach(pthread_self());
 
 
}
 
}
  
Line 62: Line 83:
 
static void daemon_create_(void (*func)(void)) {
 
static void daemon_create_(void (*func)(void)) {
 
     Daemon * daemon = malloc(sizeof(Daemon));
 
     Daemon * daemon = malloc(sizeof(Daemon));
     daemon->func_ = func;
+
     daemon->func_   = func;
 +
    daemon->inJoin_ = 0;
  
 
     pthread_mutex_lock(&daemons_mutex_);
 
     pthread_mutex_lock(&daemons_mutex_);
Line 89: Line 111:
 
         pthread_t hd;
 
         pthread_t hd;
 
         memcpy(&hd, &firstDaemon_->hd_, sizeof(pthread_t));
 
         memcpy(&hd, &firstDaemon_->hd_, sizeof(pthread_t));
 +
        firstDaemon_->inJoin_ = 1;
  
 
         pthread_mutex_unlock(&daemons_mutex_);
 
         pthread_mutex_unlock(&daemons_mutex_);
  
 
         // We may want to cancel a thread actively during termination:
 
         // We may want to cancel a thread actively during termination:
         pthread_cancel(hd);
+
         my_pthread_cancel(hd);
 
         // respectively
 
         // respectively
 
         //pthread_kill();
 
         //pthread_kill();
  
         pthread_join(hd, NULL);
+
         my_pthread_join(hd, NULL);
 
         fprintf(stderr, "# ");
 
         fprintf(stderr, "# ");
  
Line 118: Line 141:
 
     pthread_mutex_unlock(&activity_mutex_);
 
     pthread_mutex_unlock(&activity_mutex_);
  
  // Terminate the process, if this was the last "activity"!
+
    // Terminate the process, if this was the last "activity"!
 
     if (use_exit)  
 
     if (use_exit)  
 
         exit(0);
 
         exit(0);

Revision as of 09:01, 28 September 2007

[cpp] // // gcc -g example.c -o main.bin -lpthread //

  1. include <stdlib.h>
  2. include <stdio.h>
  3. include <pthread.h>
  4. include <string.h>


void my_pthread_cancel(pthread_t thread) {

   int res;
   if (res = pthread_cancel(thread)) {
       fprintf(stderr, "%s - %s\n", __PRETTY_FUNCTION__, strerror(res));
       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       inJoin_;

};

static pthread_mutex_t daemons_mutex_ = PTHREAD_MUTEX_INITIALIZER; static Daemon * firstDaemon_ = NULL; static unsigned int daemons_ = 0;

/* 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_;


   /* This daemon is not in the list of daemons anymore, 
      and therefor can't be joined, except if acively cancelled. */
   if (!daemon->inJoin_)
       pthread_detach(pthread_self());
   pthread_mutex_unlock(&daemons_mutex_);
   free(daemon);

}

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;
   daemon->inJoin_ = 0;
   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));
       firstDaemon_->inJoin_ = 1;
       pthread_mutex_unlock(&daemons_mutex_);
       // We may want to cancel a thread actively during termination:
       my_pthread_cancel(hd);
       // respectively
       //pthread_kill();
       my_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;

}

Personal tools