/home/oan/prosjekt/gotools/segmentation/gpl_distro/lsseg_1.0_gpl/src/simplethreads.C

Go to the documentation of this file.
00001 //===========================================================================
00002 // The Level-Set Segmentation Library (LSSEG)
00003 //
00004 //
00005 // Copyright (C) 2000-2005 SINTEF ICT, Applied Mathematics, Norway.
00006 //
00007 // This program is free software; you can redistribute it and/or          
00008 // modify it under the terms of the GNU General Public License            
00009 // as published by the Free Software Foundation version 2 of the License. 
00010 //
00011 // This program is distributed in the hope that it will be useful,        
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of         
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          
00014 // GNU General Public License for more details.                           
00015 //
00016 // You should have received a copy of the GNU General Public License      
00017 // along with this program; if not, write to the Free Software            
00018 // Foundation, Inc.,                                                      
00019 // 59 Temple Place - Suite 330,                                           
00020 // Boston, MA  02111-1307, USA.                                           
00021 //
00022 // Contact information: e-mail: tor.dokken@sintef.no                      
00023 // SINTEF ICT, Department of Applied Mathematics,                         
00024 // P.O. Box 124 Blindern,                                                 
00025 // 0314 Oslo, Norway.                                                     
00026 // 
00027 //
00028 // Other licenses are also available for this software, notably licenses
00029 // for:
00030 // - Building commercial software.                                        
00031 // - Building software whose source code you wish to keep private.        
00032 //
00033 //===========================================================================
00034 //#ifdef tor
00035 //#  include <vector>
00036 //#else
00037 //#  include <vector.h>
00038 //#endif
00039 
00042 #include <vector>
00043 
00044 #include "simplethreads.h"
00045 
00046 
00047 
00048 
00049 
00050 
00051 //
00052 // This module is more or less stable, so let's force this off.
00053 //
00054 #undef DEBUG  
00055 #undef DEBUG_HEAVY
00056 
00057 
00058 
00059 
00060 
00062 struct thread_data_struct
00064 {
00065   int thread_id;
00066   pthread_mutex_t *mutex;
00067   char *job_flag;               // Pointer to array of flags, where
00068                                 // 0=not started on, 1=done, or being done.
00069   int *jobs_done;
00070   int jobs;
00071   void (*do_a_job)(const int, const int, void * const, void * const);
00072   void *individual_job_data;    // Note that this is an array of structs,
00073                                 // which 'do_a_job' must be able to correctly
00074                                 // handle! If this is NULL, it means that there
00075                                 // is no individual job data, which might be
00076                                 // the case for simple jobs.
00077   void *results;                // The same applies here. This is an array
00078                                 // which do_a_job must know how to use.
00079                                 // Note that neither of 'individual_job_data'
00080                                 // and 'results' is locked/unlocked, so jobs
00081                                 // should not share their elemnts of these
00082                                 // arrays with each other!
00083   bool show_progress; // 051101
00084 };
00085 
00086 
00087 
00088 
00089 
00090 
00091 //======================================================================
00092 //
00093 // This is not meant to be called directly by the user, instead the
00094 // user supplies the 'do_a_job' function to 'do_threaded_jobs'.
00095 //
00096 // In this function, a thread tries to do as many "jobs" as possible,
00097 // until all jobs are done (by itself or other threads.)
00098 //
00099 // 050620: So, if I understand my own comment correctly, 
00100 //         'do_threaded_jobs' is rather a wrapper around 'do_jobs'...
00101 //
00102 //======================================================================
00103 
00104 void *do_jobs(void *thread_data_ptr)
00105 {
00106   //
00107   // Some convenient aliases:
00108   //
00109   const int &thread_id=((thread_data_struct *)thread_data_ptr)->thread_id;
00110   int *jobs_done=((thread_data_struct *)thread_data_ptr)->jobs_done;
00111   int jobs=((thread_data_struct *)thread_data_ptr)->jobs;
00112   void * const results=((thread_data_struct *)thread_data_ptr)->results;
00113   pthread_mutex_t *mutex=((thread_data_struct *)thread_data_ptr)->mutex;
00114   char *job_flag=((thread_data_struct *)thread_data_ptr)->job_flag;
00115   void (*do_a_job)(const int, const int, void * const, void * const)=
00116     ((thread_data_struct *)thread_data_ptr)->do_a_job;
00117   void *individual_job_data=
00118     ((thread_data_struct *)thread_data_ptr)->individual_job_data;
00119   bool show_progress=((thread_data_struct *)thread_data_ptr)->show_progress;
00120 
00121 #ifdef DEBUG
00122   printf("simplethreads: do_jobs called for thread %d.\n", thread_id);
00123 #endif
00124   
00125   //
00126   // Lock all shared data, so that it is not changed by another thread
00127   // while we look for a new job.
00128   //
00129 #ifdef DEBUG_HEAVY
00130   printf("simplethreads: do_jobs(%d) waiting for lock.\n", thread_id);
00131 #endif
00132   int err;
00133   if ((err=pthread_mutex_lock(mutex))!=0)
00134     CRIT_ERR(printf("mutex_lock error: %d (thread=%d)\n", err, thread_id));
00135 #ifdef DEBUG_HEAVY
00136   printf("simplethreads: do_jobs(%d) got lock.\n", thread_id);
00137 #endif
00138 
00139   int stride=std::max(jobs/20, 1);
00140 
00141   //
00142   // Look for a job, if not all are done. This we will continue to do,
00143   // as long as there are jobs to be done. Note the locking of the
00144   // shared data across the scope boundaries both at the start and end
00145   // of this while block!
00146   //
00147   while (*jobs_done<jobs)
00148     {
00149       int i;
00150       for (i=0; (i<jobs) && (job_flag[i]!=0); )
00151         i++;
00152       if (i==jobs)
00153         CRIT_ERR(puts("Shouldn't happen!"));
00154 
00155       //
00156       // Ok, we have a job to do, let's do it, after we have updated
00157       // the job_flag array, and released it, in effect letting the
00158       // other threads know that *we* are the ones doing this
00159       // particular job.
00160       //
00161       job_flag[i]=1; // Meaning "done, or being done".
00162       (*jobs_done)++;
00163       if ((show_progress) && ((*jobs_done)%stride==0))
00164         printf("%d ", (jobs-(*jobs_done))/stride), fflush(stdout);
00165 #ifdef DEBUG_HEAVY
00166   printf("simplethreads: do_jobs(%d) unlocking.\n", thread_id);
00167 #endif
00168       if ((err=pthread_mutex_unlock(mutex))!=0)
00169         CRIT_ERR(printf("mutex_unlock err: %d (thread %d)\n", err, thread_id));
00170 #ifdef DEBUG_HEAVY
00171   printf("simplethreads: do_jobs(%d) unlocked.\n", thread_id);
00172 #endif
00173       
00174       //
00175       // Do the work!
00176       //
00177       do_a_job(i, thread_id, individual_job_data, results);
00178 
00179       //
00180       // Now, since we entered the scope with shared data locked, and
00181       // we have to do that again, for the next "round" of this loop,
00182       // we must now lock the data.
00183       //
00184 #ifdef DEBUG_HEAVY
00185   printf("simplethreads: do_jobs(%d) waiting for lock 2.\n", thread_id);
00186 #endif
00187       int err;
00188       if ((err=pthread_mutex_lock(mutex))!=0)
00189         CRIT_ERR(printf("mutex_lock error: %d (thread=%d)\n", err, thread_id));
00190 #ifdef DEBUG_HEAVY
00191   printf("simplethreads: do_jobs(%d) got lock 2.\n", thread_id);
00192 #endif
00193     }
00194   if (show_progress)
00195     printf("\n");
00196   
00197   //
00198   // No more work to do. Not much to do than return. But we should
00199   // remember to unlock the data, since we left the loop with the data
00200   // locked!
00201   //
00202 #ifdef DEBUG_HEAVY
00203   printf("simplethreads: do_jobs(%d) unlocking 2.\n", thread_id);
00204 #endif
00205   if ((err=pthread_mutex_unlock(mutex))!=0)
00206     CRIT_ERR(printf("mutex_unlock err: %d (thread %d)\n", err, thread_id));
00207 #ifdef DEBUG_HEAVY
00208   printf("simplethreads: do_jobs(%d) unlocked 2.\n", thread_id);
00209 #endif
00210 
00211   return NULL;
00212 
00213   //
00214   // Why shouldn't this return an int instead, since the value shall
00215   // be used as an "exit code"??? Is this some kind of bug, or relic,
00216   // in the pthreads library?
00217   //
00218 }
00219 
00220 
00221 
00222 
00223 
00224 
00225 void do_threaded_jobs(void (*do_a_job)(const int,
00226                                        const int,
00227                                        void * const,
00228                                        void * const),
00229                       void * job_data_struct_array,
00230                       const int threads,
00231                       const int jobs,
00232                       const bool show_progress,
00233                       void * const results)
00234 {
00235   // printf("Initializing %d threads for %d jobs.\n", threads, jobs);
00236 
00237   // 0=job not started, 1=done or being processed.
00238   std::vector<char> job_flag(jobs, 0);
00239   int jobs_done=0;
00240 
00241   // Used to lock the job-flag array by threads accessing it.
00242   pthread_mutex_t trace_admin_mutex;
00243   int err;
00244 #ifdef DEBUG_HEAVY
00245   printf("simplethreads: do_threaded_jobs initializing lock.\n");
00246 #endif
00247   if ((err=pthread_mutex_init(&trace_admin_mutex, NULL))!=0)
00248     CRIT_ERR(printf("pthread_mutex_init error: %d\n", err));
00249 #ifdef DEBUG_HEAVY
00250   printf("simplethreads: do_threaded_jobs initialized lock.\n");
00251 #endif
00252 
00253   //
00254   // Setting up a data-package for each thread.  Ok, there is some
00255   // unneccessary duplication of data here. Will fix some other time.
00256   //
00257   std::vector<thread_data_struct> thread_data(threads);
00258   int i;
00259   for (i=0; i<threads; i++)
00260     {
00261       thread_data[i].thread_id=i;
00262       thread_data[i].mutex=&trace_admin_mutex;
00263       thread_data[i].job_flag=&job_flag[0];
00264       thread_data[i].jobs_done=&jobs_done;
00265       thread_data[i].jobs=jobs;
00266       thread_data[i].do_a_job=do_a_job;
00267       thread_data[i].individual_job_data=job_data_struct_array;
00268       thread_data[i].results=results;
00269       thread_data[i].show_progress=show_progress;
00270     }
00271 
00272   //
00273   // Forking off the threads. They will immediately start working on
00274   // the individual jobs, and they will all return when there are no
00275   // more jobs to do.
00276   //
00277   std::vector<pthread_t> thread(threads);
00278   for (i=0; i<threads; i++)
00279     {
00280 #ifdef DEBUG_HEAVY
00281       printf("simplethreads: do_threaded_jobs creating thread %d.\n", i);
00282 #endif
00283       if ((err=pthread_create(&thread[i],
00284                               NULL,
00285                               do_jobs,
00286                               (void *)&(thread_data[i])))!=0)
00287         CRIT_ERR(printf("pthread_create error: %d\n", err));
00288 #ifdef DEBUG_HEAVY
00289       printf("simplethreads: do_threaded_jobs created thread %d.\n", i);
00290 #endif
00291     }
00292 
00293   //
00294   // Now we simply wait for all the threads to finish.
00295   //
00296 
00297 //    {
00298 //      int i;
00299 //      double x=0.0;
00300 //      for (i=0; i<1000000000; i++)
00301 //        {
00302 //      x=sin(x+0.01);
00303 //      if (i%1000000==0) printf("z=%f\n", x);
00304 //        }
00305 //      puts("z ferdig");
00306 //      for (i=0; i<1000000000; i++)
00307 //        {
00308 //      x=sin(x+0.01);
00309 //      if (i%1000000==0) printf("zz=%f\n", x);
00310 //        }
00311 //      puts("zz ferdig");
00312 //    }
00313 
00314 
00315 
00316   for (i=0; i<threads; i++)
00317     {
00318       void *retval;
00319 #ifdef DEBUG
00320       printf("simplethreads: do_threaded_jobs joining thread %d.\n", i);
00321 #endif
00322       if ((err=pthread_join(thread[i], &retval))!=0)
00323         CRIT_ERR(printf("pthread_join error on thread %d: %d\n", i, err));
00324 #ifdef DEBUG
00325       printf("simplethreads: do_threaded_jobs joined thread %d.\n", i);
00326 #endif
00327     }
00328 #ifdef DEBUG_HEAVY
00329   printf("simplethreads: do_threaded_jobs destroying mutex.\n");
00330 #endif
00331   if ((err=pthread_mutex_destroy(&trace_admin_mutex))!=0)
00332     CRIT_ERR(printf("pthread_mutex_destroy error: %d\n", err));
00333 #ifdef DEBUG_HEAVY
00334   printf("simplethreads: do_threaded_jobs destroyed mutex.\n");
00335 #endif
00336 
00337   //
00338   // And that was it.
00339   //
00340   // puts("All threads now joined and terminated.");
00341 }
00342 
00343 
00344 
00345 
00346 
00347 
00348 //======================================================================
00349 //
00350 // 050620: Starting a new version which will use "condition variables".
00351 //         Don't know how I could have missed this. Or was it added to 
00352 //         pthreads after I made the first version many years ago?
00353 //         Or maybe it was not in 'linuxthreads'???
00354 //
00355 //         I think my first implementation does exactly what it should,
00356 //         and what usage of condition variables will do, but maybe
00357 //         with a small (large?!) overhead due to the constant polling
00358 //         in the "look for job" loop... Should be interesting to test
00359 //         after the new version is working. (Maybe with the raytracing
00360 //         code?)
00361 //
00362 //         Are the three classic examples, "producer/consumer",
00363 //         "reader/writer" and "dining philosophers" really the same?
00364 //         If not, which one (if any) do we have here?
00365 //         "Reader/writer"?
00366 //
00367 //         Hmm... When thinking more about this, maybe there is no use
00368 //         for condition variables in just this case... Think maybe not...
00369 //
00370 //======================================================================

Generated on Tue Nov 28 18:35:47 2006 for lsseg by  doxygen 1.4.7