Simple tools for multi threading / objects in plain C Snapshot
cbarrier.c
Go to the documentation of this file.
00001 /* Copyright (c) Michael Moser (2011) . 3-clause BSD License applies */
00002 
00003 #include <pthread.h>
00004 #include <sched.h>
00005 
00006 #include "cbarrier.h"
00007 #include <butils/errorp.h>
00008 #include <stdio.h>
00009 
00010 static int CYCLIC_BARRIER_wait_for_all_to_finish(CYCLIC_BARRIER *cond);
00011 
00012 //------------------------------------------------------------------
00013 void CYCLIC_BARRIER_init(CYCLIC_BARRIER *cond, int num)
00014 {
00015     int rt;
00016 
00017     cond->initial_count = num;
00018     cond->tcount = num;
00019     cond->is_finished = 0;
00020     cond->left = num;
00021  
00022     if ((rt = pthread_mutex_init(&cond->mutex,0)) != 0) {
00023        errorp( rt, "pthread_mutex init failed");
00024     }
00025     if ((rt = pthread_cond_init(&cond->cond, 0)) != 0) {
00026        errorp( rt, "pthread_cond init failed");
00027     }
00028 }
00029 
00030 
00031 
00032 int  CYCLIC_BARRIER_reset(CYCLIC_BARRIER *cond)
00033 {
00034     int rt;
00035 
00036     if (CYCLIC_BARRIER_wait_for_all_to_finish(cond)) {
00037       return -1;
00038     }
00039   
00040     if ((rt = pthread_mutex_lock(&cond->mutex)) != 0) {
00041       errorp(rt, "CYCLIC_BARRIER: pthread_mutex lock failed");
00042       return -1;
00043     }
00044     
00045     cond->tcount = cond->initial_count;
00046     cond->left = cond->initial_count;
00047     cond->is_finished = 0;
00048    
00049     if ((rt = pthread_mutex_unlock(&cond->mutex)) != 0) {
00050       errorp(rt, "CYCLIC_BARRIER: pthread_mutex_unlock failed");
00051       return -1;
00052     }
00053 
00054     return 0;
00055 }
00056 
00057 int CYCLIC_BARRIER_free(CYCLIC_BARRIER*cond)
00058 {
00059     int rt = 0;
00060    
00061     if (CYCLIC_BARRIER_wait_for_all_to_finish(cond)) {
00062       return -1;
00063     }
00064     
00065     if ((rt = pthread_cond_destroy( &cond->cond )) != 0 ) {
00066       errorp(rt, "CYCLIC_BARRIER: pthread_cond_destroy failed");
00067     }
00068     if ((rt = pthread_mutex_destroy( &cond->mutex )) != 0 ) {
00069       errorp(rt, "CYCLIC_BARRIER: pthread_mutext destroy failed");
00070     }
00071  
00072     return rt;
00073 }
00074 
00075 
00076  int CYCLIC_BARRIER_await(CYCLIC_BARRIER *cond)
00077 {
00078     int rt = 0;
00079 
00080 
00081     if ((rt = pthread_mutex_lock(&cond->mutex)) != 0) {
00082       errorp(rt, "CYCLIC_BARRIER: pthread_mutex lock failed");
00083       return -1;
00084     }
00085     if (! cond->is_finished ) {
00086       --cond->tcount;
00087       if (cond->tcount > 0) {
00088          if ((rt = pthread_cond_wait(&cond->cond,&cond->mutex)) != 0) {
00089            errorp(rt, "CYCLIC_BARRIER: pthread_cond_wait failed");
00090          }
00091       } else {
00092          cond-> is_finished = 1;
00093          if ((rt = pthread_cond_broadcast(&cond->cond)) != 0) {
00094            errorp(rt, "CYCLIC_BARRIER: pthread_cond_broadcast failed");
00095          }
00096       }
00097     }
00098 
00099     cond->left--;
00100     
00101     if ((rt = pthread_mutex_unlock(&cond->mutex)) != 0) {
00102       errorp(rt, "CYCLIC_BARRIER: pthread_mutex_unlock failed");
00103     }
00104 
00105     return rt;
00106  }
00107 
00108 
00109 static int CYCLIC_BARRIER_wait_for_all_to_finish(CYCLIC_BARRIER *cond)
00110 {
00111     int rt, left;
00112     int finished, count, init_count;
00113    
00114     if ((rt = pthread_mutex_lock(&cond->mutex)) != 0) {
00115       errorp(rt, "CYCLIC_BARRIER: pthread_mutex lock failed");
00116       return -1;
00117     }
00118     
00119     finished = cond->is_finished;
00120     count = cond->tcount;
00121     init_count = cond->initial_count;
00122     
00123     if ((rt = pthread_mutex_unlock(&cond->mutex)) != 0) {
00124       errorp(rt, "CYCLIC_BARRIER: pthread_mutex_unlock failed");
00125     }
00126 
00127     if (!finished) {
00128       errorp(-1,"Can't finish, not all parties have reached common synchronisation point, %d parties out of %d not finished", count, init_count);
00129       return -1;
00130     }
00131 
00132 
00133    do {
00134       if ((rt = pthread_mutex_lock(&cond->mutex)) != 0) {
00135         errorp(rt, "CYCLIC_BARRIER: pthread_mutex lock failed");
00136         return -1;
00137       }
00138     
00139       left = cond->left;
00140     
00141       if ((rt = pthread_mutex_unlock(&cond->mutex)) != 0) {
00142         errorp(rt, "CYCLIC_BARRIER: pthread_mutex_unlock failed");
00143         return -1;
00144       }
00145 
00146       if (left != 0) {
00147         sched_yield();
00148       }
00149 
00150     } while ( left != 0);
00151 
00152     return 0;
00153 }
00154 
00155 
00156 
00157