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

From Apache OpenOffice Wiki
Jump to: navigation, search
(Library Example)
 
m (.)
Line 1: Line 1:
 +
===The Main Program===
 
<code>[cpp]
 
<code>[cpp]
//
+
/*
// gcc -Wall -g main.c -o main.bin -lpthread -ldl
+
** 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; // The "main" thread is the first "activity".
+
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"!
+
     /* 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 void (* pdaemon_create_)(void (*func)(void));
+
static daemon_create_t    * pdaemon_create_;
 
+
static daemons_getCount_t * pdaemons_getCount_;
static int (* pdaemons_getCount_)(void);
+
 
+
  
  
Line 69: Line 70:
 
         log_threads();
 
         log_threads();
  
         sleep(1); /* This is a cancellation point. */
+
         /* 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) {
     void (* pdaemons_cancelAndJoin)(void) = dlsym(dlhd_, "daemons_cancelAndJoin");
+
     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
// gcc -Wall -g library.c -shared -o library.so -lpthread
+
#  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,
+
         /* There seems to be an issue on Linux with pthread_cancel,
         // returning an error in case "thread" has already terminated,  
+
         ** returning an error in case "thread" has already terminated,  
         // though not joined.
+
         ** though not joined. */
//        abort();
+
/*        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 daemon_finish(Daemon * daemon) {
+
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 * daemon_func(Daemon * daemon) {
+
static void * daemon_func_(Daemon * daemon) {
     pthread_cleanup_push((void (*)(void *))daemon_finish, daemon);
+
     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". */
  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 *))daemon_func, daemon);
+
     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.
+
/* 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
+
         /* respectively */
         //pthread_kill();
+
         /*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
  • /
  1. include "library.h"
  1. include <stdlib.h>
  2. include <stdio.h>
  3. include <pthread.h>
  4. include <string.h>
  5. include <unistd.h>
  6. 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]

  1. ifndef library_h_included
  2. 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);


  1. endif

Library Implementation

[cpp] /*

    • gcc -Wall -g library.c -shared -o library.so -lpthread
  • /
  1. include "library.h"
  1. include <stdlib.h>
  2. include <stdio.h>
  3. include <pthread.h>
  4. include <string.h>
  5. 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");

}

Personal tools