Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

/ray/src/lib/threads/thread.cc

Go to the documentation of this file.
00001 /*
00002  * lib/threads/thread.cc
00003  * 
00004  * Implementing thread class for multi-threaded applications. 
00005  * 
00006  * Copyright (c) 2004 by Wolfgang Wieser ] wwieser (a) gmx <*> de [ 
00007  * 
00008  * This file may be distributed and/or modified under the terms of the 
00009  * GNU General Public License version 2 as published by the Free Software 
00010  * Foundation. (See COPYING.GPL for details.)
00011  * 
00012  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00013  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00014  * 
00015  */
00016 
00017 #include "thread.h"
00018 
00019 
00020 // Initialize static data: 
00021 ThreadKernel *ThreadKernel::kernel=NULL;
00022 
00023 
00024 int ThreadKernel::_NRunningThreads()
00025 {
00026     mutex.lock();
00027     int n=nrunning;
00028     mutex.unlock();
00029     
00030     return(n);
00031 }
00032 
00033 
00034 void *ThreadKernel::_ThreadFuncWrapper(void *ptr)
00035 {
00036 //fprintf(stderr,"WRAP %p...\n",ptr);
00037     // This function is executed by the newly created thread in that new 
00038     // thread context. 
00039     ExecutionThread *ethread=(ExecutionThread*)ptr;
00040     
00041     // Add to the list of threads. 
00042     TNode *tn=new TNode();
00043     tn->thread=g_thread_self();
00044     tn->execthread=ethread;
00045     
00046     mutex.lock();
00047     threadlist.append(tn);
00048     ++nrunning;
00049     mutex.unlock();
00050     
00051     // Well, this should be thread-safe :)
00052     g_private_set(phook,tn);
00053     
00054     // Attach information to the ExecutionThread: 
00055     bool rv=g_atomic_pointer_compare_and_exchange(
00056         (gpointer*)&ethread->handle,NULL,tn);
00057     CritAssert(rv);  // critical for thread safety
00058     
00059     // Actually "run" the thread function: 
00060     ethread->run();
00061     
00062 //fprintf(stderr,"RUN %p done.\n",ethread);
00063     return(NULL);
00064 }
00065 
00066 void *ThreadKernel::ThreadFuncWrapper(void *ptr)
00067 {
00068     // (Static version.)
00069     return(ThreadKernel::kernel->_ThreadFuncWrapper(ptr));
00070 }
00071 
00072 
00073 void ThreadKernel::_PhookNotifier(gpointer ptr)
00074 {
00075 //fprintf(stderr,"_PhookNotifier(%p %s)",ptr,ptr==kernel ? "kernel" : "");
00076     
00077     // This means that any thread has exited. 
00078     // We are executed in this thread's context. 
00079     // Let's see which one. 
00080     if(ptr==this)
00081     {
00082         // Oops, the kernel exited? This should not happen. 
00083         CritAssert(0);
00084         return;
00085     }
00086     
00087     TNode *tn=(TNode*)ptr;
00088     CritAssert(tn->thread==g_thread_self());
00089     
00090     mutex.lock();
00091     
00092     // We must tell the ExecutionThread class about that, 
00093     // if it still exists. 
00094     if(tn->execthread)
00095     {
00096         bool rv=g_atomic_pointer_compare_and_exchange(
00097             (gpointer*)&tn->execthread->handle,tn,NULL);
00098         // If this assert fails, someone (probably ExecutionThread) must 
00099         // have modified the handle pointer which he is not allowed to. 
00100         CritAssert(rv);  // critical for thread safety
00101         
00102         // This is all. The ExecutionThread now knows that the thread exited. 
00103     }
00104     
00105     // The associated thread is no longer valid. 
00106     // (Well, currently it still is but only for a few CPU cycles :)
00107     tn->thread=NULL;
00108     
00109     // And remove the thread from the list: 
00110     threadlist.dequeue(tn);
00111     --nrunning;
00112     
00113     mutex.unlock();
00114     
00115     // Operator delete should be thread-save by itself :)
00116     delete tn;
00117 }
00118 
00119 void ThreadKernel::PhookNotifier(gpointer ptr)
00120 {
00121     // (Static version.)
00122     ThreadKernel::kernel->_PhookNotifier(ptr);
00123 }
00124 
00125 
00126 void ThreadKernel::_unregister(ExecutionThread *et)
00127 {
00128     // In case the thread kernel was already destroyed, there is nothing 
00129     // to do. 
00130     if(!g_atomic_pointer_get((gpointer*)&kernel))  return;
00131     
00132     // It is important that all this is protected by a mutex. 
00133     mutex.lock();
00134     
00135     if(this && et->handle)
00136     {
00137         // Clear handle in the execution thread. 
00138         TNode *tn=et->handle;
00139         et->handle=NULL;
00140         
00141         // Clear attached ExecutionThread since it does no longer exist. 
00142         tn->execthread=NULL;
00143     }
00144     
00145     mutex.unlock();
00146 }
00147 
00148 
00149 void ThreadKernel::init()
00150 {
00151     // The TheadKernel will itself set the static data. 
00152     new ThreadKernel();
00153 }
00154 
00155 void ThreadKernel::cleanup()
00156 {
00157     if(ThreadKernel::kernel)
00158     {  delete ThreadKernel::kernel;  }  // Destroctor will set to NULL. 
00159 }
00160 
00161 
00162 ThreadKernel::ThreadKernel() : 
00163     mutex(),
00164     threadlist(),
00165     nrunning(0)
00166 {
00167     // Initialize the thread system. 
00168     g_thread_init(NULL);
00169     CritAssert(g_thread_supported());  // critical
00170     
00171     // Play with the mutex :)
00172     mutex.lock();
00173     
00174     // There may be a limited number of GPrivate but this should not fail 
00175     // since we've just initialized the thread system and hence there 
00176     // should not have ben much use of GPrivate yet. 
00177     phook=g_private_new(&PhookNotifier);
00178     CritAssert(phook);  // critical
00179     
00180     g_private_set(phook,this);
00181     
00182     Assert(!ThreadKernel::kernel);
00183     ThreadKernel::kernel=this;
00184     
00185     mutex.unlock();
00186 }
00187 
00188 ThreadKernel::~ThreadKernel()
00189 {
00190     mutex.lock();
00191     
00192     // Free all elements of the thread list. There should be none. 
00193     // If this assert fails, there are still threads running. 
00194     // You may not clean up the thread kernel in such a case. 
00195     CritAssert(threadlist.IsEmpty());
00196     while(!threadlist.IsEmpty())
00197     {
00198         delete threadlist.PopFirst();
00199         --nrunning;
00200     }
00201     
00202     // GPrivate cannot be destroyed. 
00203     g_private_set(phook,NULL);
00204     phook=NULL;
00205     
00206     Assert(ThreadKernel::kernel==this);
00207     ThreadKernel::kernel=NULL;
00208     
00209     mutex.unlock();
00210 }
00211 
00212 
00213 //------------------------------------------------------------------------------
00214 
00215 int ExecutionThread::start()
00216 {
00217     if(g_atomic_pointer_get(&handle))  return(-2);
00218     
00219     // Only non-joinable threads are supported. We get to know when 
00220     // they exit in any case and can do better than simple joining 
00221     // using a condition or a semaphore. 
00222     //GError *err=NULL;
00223     GThread *thread=g_thread_create(
00224         &ThreadKernel::ThreadFuncWrapper,this,
00225         /*joinable=*/0,/*&err*/NULL);
00226     if(!thread)
00227     {
00229         // g_error_free(err);
00230         return(-3);
00231     }
00232     
00237     for(;;)
00238     {
00239         if(g_atomic_pointer_get(&handle)) break;
00240         g_thread_yield();
00241     }
00242     
00243     return(0);
00244 }
00245 
00246 
00247 void ExecutionThread::exit()
00248 {
00249     g_thread_exit(NULL);
00250 }
00251 
00252 
00253 void ExecutionThread::yield()
00254 {
00255     g_thread_yield();
00256 }
00257 
00258 
00259 void ExecutionThread::run()
00260 {
00261     // Hmm... default is to do nothing :)
00262     //fprintf(stderr,"You'd better do something useful with the thread!\n");
00263     return;
00264 }
00265 
00266 
00267 
00268 ExecutionThread::ExecutionThread()
00269 {
00270     handle=NULL;
00271 }
00272 
00273 ExecutionThread::~ExecutionThread()
00274 {
00275     // Unregister at the ThreadKernel. 
00276     ThreadKernel::unregister(this);
00277 }
00278 
00279 
00280 #if 0
00281 #include <stdio.h>  /* test program */
00282 #include <sched.h>
00283 
00284 // Test program. 
00285 //  g++ lib_threads.a  -o test `pkg-config --libs gthread-2.0`
00286 
00287 class MyThreadA : public ExecutionThread
00288 {
00289     void run()
00290     {
00291         for(int i=0; i<100; i++)
00292         {
00293             fprintf(stderr,"runA\t");
00294             yield();
00295         }
00296     }
00297 };
00298 
00299 class MyThreadB : public ExecutionThread
00300 {
00301     void run()
00302     {
00303         for(int i=0; i<100; i++)
00304         {
00305             fprintf(stderr,"runB\t");
00306             yield();
00307             if(i==40)  exit();
00308         }
00309     }
00310 };
00311 
00312 
00313 int main()
00314 {
00315     ThreadKernel::init();
00316     
00317     MyThreadA A;
00318     MyThreadB B;
00319     fprintf(stderr,"A=%p, B=%p\n",&A,&B);
00320     
00321     A.start();
00322     B.start();
00323     
00324     for(int i=0; i<50; i++)
00325     {
00326         sched_yield();
00327         A.start();
00328         if(!B.running())
00329         {
00330             fprintf(stderr,"B-OUT!");
00331             B.start();
00332         }
00333     }
00334     
00335     fprintf(stderr,"Press any key..."); getchar();
00336     
00337     ThreadKernel::cleanup();
00338     
00339     fprintf(stderr,"Exiting\n");
00340     return(0);
00341 }
00342 
00343 #endif

Generated on Sat Feb 19 22:33:46 2005 for Ray by doxygen 1.3.5