Simple tools for multi threading / objects in plain C Snapshot
|
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