]> Creatis software - creaImageIO.git/commitdiff
Qt improvement
authorFrederic Cervenansky <Frederic.Cervenansky@creatis.insa-lyon.fr>
Wed, 20 Oct 2010 16:14:34 +0000 (16:14 +0000)
committerFrederic Cervenansky <Frederic.Cervenansky@creatis.insa-lyon.fr>
Wed, 20 Oct 2010 16:14:34 +0000 (16:14 +0000)
appli/TestQtGimmick/main.cxx
src/CMakeLists.txt
src/creaImageIOGimmickView.h
src/creaImageIOQMultiThreadImageReader.cpp [new file with mode: 0644]
src/creaImageIOQMultiThreadImageReader.h [new file with mode: 0644]

index 74c0b238d44f2e6927279e0923ea5ad4276ed5b5..e8809f63a47f5868f1124971a61bd4ce14b25b52 100644 (file)
@@ -1,5 +1,5 @@
 #include <QApplication>
-#include <creaImageIOQtGimmickReaderDialog.h>
+#include "creaImageIOQTGimmickReaderDialog.h"
 //#include "vtkMetaImageReader.h"
 
 
index 9ae8fc681c667bc1bc28ff0d96fb818d22de82bc..05d6b096cecdc1295aead37a9c796452bf31a5ba 100644 (file)
@@ -53,8 +53,8 @@ FILE(GLOB SOURCES_CREAIMAGEIO_IMG_READER
          creaImageIOImageReader.cpp
          creaImageIOUltrasonixImageReader.cpp
          creaImageIOVtkImageReader.cpp
-         creaImageIOMultiThreadImageReader.cpp
-         ${SOURCES_CREAIMAGEIO_IMG_DICOM_READER}
+         creaImageIOQMultiThreadImageReader.cpp
+                 ${SOURCES_CREAIMAGEIO_IMG_DICOM_READER}
          )
 
 # The wxWidgets-based components
@@ -81,6 +81,7 @@ FILE(GLOB SOURCES_CREAIMAGEIO_WX
          creaImageIOExternalGimmick.cpp
          BlockScopeWxApp.cpp
         creaImageIOListener.cpp
+        creaImageIOMultiThreadImageReader.cpp
     )
          SOURCE_GROUP("Source Files\\GUI" FILES ${SOURCES_CREAIMAGEIO_WX})
 endif()
@@ -89,7 +90,8 @@ endif()
 IF (USE_QT4)
        #cpp
        FILE(GLOB QT_CPP 
-               QtGUI/*.cpp QtGUI/*.cxx
+               QtGUI/*.cpp 
+               QtGUI/*.cxx
                )
        
        # headers
@@ -123,7 +125,8 @@ ENDIF(USE_XERCES)
 
 
 # Header Files   
-FILE(GLOB HEADER_CREAIMAGEIO creaImageIOImagePointerHolder.h  CppSQLite3.h)
+FILE(GLOB HEADER_CREAIMAGEIO #creaImageIOImagePointerHolder.h  CppSQLite3.h)
+#*.h)
 FILE(GLOB SOURCES_CREAIMAGEIO_PACS PACS/*.cpp)
 FILE(GLOB HEADER_CREAIMAGEIO_PACS PACS/*.h)
 
index fed6e1700e720b69e032f82f79f596337579e638..d41ea1a6e2cf2f6c73c707db58bc5f361b29c614 100644 (file)
@@ -8,7 +8,14 @@
 
 //#include <map>
 #include <vtkImageData.h>
+#if defined (USE_WXWIDGETS)
 #include <creaImageIOMultiThreadImageReader.h>
+#endif
+
+#if defined(USE_QT4)
+#include <creaImageIOQMultiThreadImageReader.h>
+#endif
+
 
 // Signal/slot mechanism for progress events
 #include <boost/signal.hpp>
diff --git a/src/creaImageIOQMultiThreadImageReader.cpp b/src/creaImageIOQMultiThreadImageReader.cpp
new file mode 100644 (file)
index 0000000..c0a9f4d
--- /dev/null
@@ -0,0 +1,645 @@
+#include <creaImageIOQMultiThreadImageReader.h>
+#include <creaImageIOImageReader.h>
+//#include <wx/utils.h>
+#include <QThread>
+#include <creaImageIOSystem.h>
+
+#include <creaImageIOGimmick.h>
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#endif
+namespace creaImageIO
+{
+
+  //=====================================================================
+  void MultiThreadImageReaderUser::MultiThreadImageReaderSendEvent
+  ( const std::string& filename,
+    EventType type,
+    vtkImageData* image)
+  {
+    QMutexLocker lock(&mMultiThreadImageReaderUserMutex);
+
+    this->OnMultiThreadImageReaderEvent(filename,type,image);
+  }
+  //=====================================================================
+
+  //=====================================================================
+  class ThreadedImageReader: public QThread
+  {
+  public:
+    ThreadedImageReader(MultiThreadImageReader* tir) :
+      mMultiThreadImageReader(tir)
+    {}
+
+    void* Entry();
+    void  OnExit();
+
+    vtkImageData* Read(const std::string& filename);
+    
+       struct deleter
+       {
+               void operator()(ThreadedImageReader* p)
+               {
+                       delete p;
+               }
+       };
+       friend struct deleter;
+
+
+  private:
+    ImageReader mReader;
+    MultiThreadImageReader* mMultiThreadImageReader;
+       
+  };
+
+  //=====================================================================
+
+  
+  //=====================================================================
+  MultiThreadImageReader::MultiThreadImageReader(int number_of_threads)
+    : //mDoNotSignal(false),
+      mReader(0),
+      mTotalMem(0),
+      mTotalMemMax(1000000)
+  {
+    //    std::cout << "#### MultiThreadImageReader::MultiThreadImageReader("
+    //       << " #threads= " << number_of_threads <<" )"<<std::endl;
+
+         mDone = false;
+    // Create the threads
+    for (int i=0; i<number_of_threads; i++) 
+      {
+                 //ThreadedImageReader* t = new ThreadedImageReader(this);
+                 boost::shared_ptr<ThreadedImageReader> t(new ThreadedImageReader(this), ThreadedImageReader::deleter());
+       mThreadedImageReaderList.push_back(t);
+        std::cout << "  ===> Thread "<<i
+                     <<" successfully added"<< std::endl;
+      }
+    mNumberOfThreadedReadersRunning = 0;
+    // Init the queue
+    mQueue.set(mComparator);
+    mQueue.set(mIndexer);
+    // 
+    // no thread : alloc self reader
+//    if (number_of_threads==0)
+//      {
+       mReader = new ImageReader();
+//      }
+  }
+  //=====================================================================
+
+
+  //=====================================================================
+  bool MultiThreadImageReader::Start()
+  {
+
+    //    std::cout << "#### MultiThreadImageReader::Start()"
+    //               <<std::endl;
+         if (mNumberOfThreadedReadersRunning > 0) return true;
+         
+    ThreadedImageReaderListType::iterator i;
+    for (i =mThreadedImageReaderList.begin();
+        i!=mThreadedImageReaderList.end();
+        i++)
+      {
+       (*i)->start();
+       if ( !(*i)->isRunning() )
+         {
+           std::cout << "ERROR starting a thread"<< std::endl;
+           return false;
+         }
+       else 
+         {
+                   std::cout << "  ===> Thread "<<(*i)->currentThreadId()
+                             <<" successfully created"<< std::endl;
+           
+         }
+      }
+    QMutexLocker locker(GetMultiThreadImageReaderUserMutex());
+    //    std::cout << "EO Start : #Threads running = "
+    //               << mNumberOfThreadedReadersRunning<<std::endl;
+
+    return true;
+  }
+  //=====================================================================
+
+  //=====================================================================
+  void MultiThreadImageReader::Stop()
+  { 
+//                 std::cout << "#### MultiThreadImageReader::Stop()"
+//           <<std::endl;
+  //  std::cout << "Sending stop order to the threads..."<<std::endl;
+         if (mDone) return;
+
+    ThreadedImageReaderListType::iterator i;
+    for (i =mThreadedImageReaderList.begin();
+        i!=mThreadedImageReaderList.end();
+        i++)
+      { std::cout << "  ===> Thread "<<(*i)->currentThreadId()
+                             <<" successfully stopped"<< std::endl;
+                 if(!(*i)->isFinished())
+                 {(*i)->wait();
+                         (*i).reset();
+                        //                       (*i)->Delete();
+                 }
+      }
+   mThreadedImageReaderList.clear();
+    // Wait a little to be sure that all threads have stopped
+    // A better way to do this ?
+    //    wxMilliSleep(1000);
+    // New method : the threads generate a stop event when they have finished
+    // We wait until all threads have stopped
+//        std::cout << "Waiting for stop signals..."<<std::endl;
+    do 
+      {
+       // Sleep a little
+       //   QThread::msleep(10);
+       // Lock
+       {
+         QMutexLocker locker(GetMultiThreadImageReaderUserMutex());
+//               std::cout << "#Threads running = "
+//                         << mNumberOfThreadedReadersRunning<<std::endl;
+         // Break if all readers have stopped
+         if (mNumberOfThreadedReadersRunning <= 0) 
+           {
+             break;
+           }
+       }
+      } 
+    while (true);
+//        std::cout << "All threads stopped : OK "<<std::endl;
+
+    ImageMapType::iterator j;
+    for (j =mImages.begin();
+        j!=mImages.end();
+        ++j)
+
+      {
+       delete j->first;
+      }
+    mImages.clear();
+       mDone = true;
+  }
+  //=====================================================================
+
+  //=====================================================================
+  MultiThreadImageReader::~MultiThreadImageReader()
+  {
+    //    std::cout << "#### MultiThreadImageReader::~MultiThreadImageReader()"
+    //       <<std::endl;
+    Stop();
+    if (mReader) delete mReader;
+       mThreadedImageReaderList.clear();
+  }
+  //=====================================================================
+
+  //=====================================================================
+  void MultiThreadImageReader::UpdateUnloadPriority(ImageToLoadPtr p, 
+                                                   int priority)
+  {
+    // not in unload queue : ciao
+    if (p->UnloadIndex()<0) return;
+    int old_prio = p->GetPriority();
+    if (priority > old_prio) 
+      {
+       p->SetPriority(priority);
+       mUnloadQueue.downsort(p->UnloadIndex());
+      }
+    else if ( old_prio > priority )
+      {
+       p->SetPriority(priority);
+       mUnloadQueue.upsort(p->UnloadIndex());
+     }
+  }
+  //=====================================================================
+  // function to read attributes for a file
+  void MultiThreadImageReader::getAttributes(const std::string filename, 
+         std::map <std::string , std::string> &infos,std::vector<std::string> i_attr)
+  {
+         mReader->getAttributes(filename, infos, i_attr);
+  }
+
+  //=====================================================================
+  void MultiThreadImageReader::Request( MultiThreadImageReaderUser* user,
+                                       const std::string& filename, 
+                                       int priority )
+  {
+       QMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
+
+         if (mNumberOfThreadedReadersRunning==0)
+//    if (mThreadedImageReaderList.size()==0) 
+      {
+       // no detached reader : use self reader
+       ImageToLoad itl(user,filename);
+       ImageMapType::iterator i = mImages.find(&itl);
+       if (i!=mImages.end())
+         {
+           ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
+           // Already inserted
+           if (pitl->GetImage() != 0)
+             {
+               // Already read
+               pitl->SetUser(user);
+               UpdateUnloadPriority(pitl,priority);
+               SignalImageRead(pitl,false);
+               return; // pitl->GetImage();
+             }
+         }
+       ImageToLoadPtr pitl = new ImageToLoad(user,filename,0);
+       mImages[pitl] = 0;
+       pitl->SetImage(mReader->ReadImage(filename));
+       UpdateUnloadPriority(pitl,priority);
+       SignalImageRead(pitl,true);
+       //      return pitl->GetImage();
+       return;
+      }
+
+    ImageToLoad itl(user,filename);
+    ImageMapType::iterator i = mImages.find(&itl);
+    if (i!=mImages.end())
+      {
+       // Already inserted
+       if (i->first->GetImage() != 0)
+         {
+           // Already read : ok :signal the user
+           UpdateUnloadPriority(i->first,priority);
+           SignalImageRead(i->first,false);
+           return;
+         }
+       /// Already requested : change the priority
+       ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
+       pitl->SetPriority(priority);
+       // Already in queue
+       if (pitl->Index()>=0) 
+         {
+           // Re-sort the queue
+           mQueue.upsort(pitl->Index());
+         }
+       // Not read but not in queue = being read = ok
+       else 
+         {
+           
+         }
+      }
+    else 
+      {
+       // Never requested before or unloaded 
+       ImageToLoadPtr pitl = new ImageToLoad(user,filename,priority);
+       mImages[pitl] = 0;
+       mQueue.insert(pitl);
+      }
+  }
+  //=====================================================================
+
+  //=====================================================================
+  void MultiThreadImageReader::OnMultiThreadImageReaderEvent
+  (const std::string& filename,
+   MultiThreadImageReaderUser::EventType e,
+   vtkImageData* image)
+  {
+    if ((e==MultiThreadImageReaderUser::ImageLoaded) &&
+       (filename == mRequestedFilename))
+      {
+       mRequestedImage = image;
+      }
+    else if (e==MultiThreadImageReaderUser::ThreadedReaderStarted)
+      {
+       mNumberOfThreadedReadersRunning++;
+       //      std::cout << "#TR=" << mNumberOfThreadedReadersRunning << std::endl;
+      }
+    else if (e==MultiThreadImageReaderUser::ThreadedReaderStopped)
+      {
+       
+                mNumberOfThreadedReadersRunning--;
+       //      std::cout << "#TR=" << mNumberOfThreadedReadersRunning << std::endl;
+      }
+  }
+  //=====================================================================
+
+  //=====================================================================
+  vtkImageData* MultiThreadImageReader::GetImage(const std::string& filename)
+  {
+        // Start();
+    //       std::cout << "** MultiThreadImageReader::GetImage('"<<filename<<"')"
+    //          <<std::endl;
+    
+    do 
+      {
+       //      wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
+               
+       //     std::cout << "** MultiThreadImageReader::GetImage('"<<filename
+       //             <<"') lock ok"
+       //               <<std::endl;
+    
+       //                if (mNumberOfThreadedReadersRunning==0)
+       //      if (mThreadedImageReaderList.size()==0)
+       if (true)
+         {
+           ImageToLoad itl(this,filename);
+           ImageMapType::iterator i = mImages.find(&itl);
+           if (i!=mImages.end())
+             {
+               ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
+               // Already inserted
+               if (pitl->GetImage() != 0)
+                 {
+                   // Already read
+                   UpdateUnloadPriority(pitl,
+                                        GetMaximalPriorityWithoutLocking()+1);
+                   return pitl->GetImage();
+                 }
+             }
+           ImageToLoadPtr pitl = new ImageToLoad(this,filename,0);
+           mImages[pitl] = 0;
+           pitl->SetImage(mReader->ReadImage(filename));
+           UpdateUnloadPriority(pitl,
+                                GetMaximalPriorityWithoutLocking()+1);
+           return pitl->GetImage();
+         }
+
+       /*      
+       mRequestedFilename = filename;
+       mRequestedImage = 0;
+       ImageToLoad itl(this,filename);
+       ImageMapType::iterator i = mImages.find(&itl);
+       if (i!=mImages.end())
+         {
+           // Already inserted in queue
+           if (i->first->GetImage() != 0)
+             {
+               // Already read : ok : return it 
+               return i->first->GetImage();
+             }
+           /// Already requested : change the priority
+             ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
+             pitl->SetPriority( GetMaximalPriorityWithoutLocking() + 1 );
+             pitl->SetUser( this );
+             // Already in queue
+             if (pitl->Index()>=0) 
+               {
+                 // Re-sort the queue
+                 mQueue.upsort(pitl->Index());
+               }
+             // Not read but not in queue = being read = ok
+             else 
+               {
+                 pitl->SetUser( this );
+               }
+         }
+       else 
+         {
+           
+           // Never requested before or unloaded 
+           ImageToLoadPtr pitl = 
+             new ImageToLoad(this,filename,
+                             GetMaximalPriorityWithoutLocking() + 1);
+           mImages[pitl] = 0;
+           mQueue.insert(pitl);
+         }
+       */
+      }
+    while (0);
+
+    //    std::cout << "Waiting..."<<std::endl;
+
+    /*
+    // Waiting that it is read
+    int n = 0;
+    do 
+      {
+       //      std::cout << n++ << std::endl;
+       wxMilliSleep(10);
+       do 
+         {
+           //      wxMutexLocker lock(mMutex);
+           wxMutexLocker lock(GetMultiThreadImageReaderUserMutex());
+           if (mRequestedImage!=0) 
+             {
+               return mRequestedImage;
+             } 
+         }
+       while (0);
+      }
+    while (true);
+    // 
+    */
+  }
+  //=====================================================================
+  
+  //=====================================================================
+  void MultiThreadImageReader::SignalImageRead(ImageToLoadPtr p, 
+                                              bool purge)
+  {
+    
+//    std::cout << "MultiThreadImageReader::SignalImageRead" <<std::endl;
+    //    std::cout << "this="<<this <<std::endl;
+    //    std::cout << "user="<<p->GetUser() <<std::endl;
+
+    if ( p->GetUser() == this ) 
+      GetMultiThreadImageReaderUserMutex()->unlock();
+
+    p->GetUser()->MultiThreadImageReaderSendEvent
+      (p->GetFilename(),
+       MultiThreadImageReaderUser::ImageLoaded,
+       p->GetImage());
+
+    /*
+      AN ATTEMPT TO UNLOAD OLDEST IMAGE IF EXCEEDED A CERTAIN MEMORY QUOTA
+      BUGGY : TO FIX 
+    */
+    if (!purge)  return;
+    GimmickMessage(5,"Image '"<<p->GetFilename()<<"' read"<<std::endl);
+
+    //    wxMutexLocker lock(GetMultiThreadImageReaderUserMutex());
+          
+    mUnloadQueue.insert(p);
+    p->GetImage()->UpdateInformation();
+    p->GetImage()->PropagateUpdateExtent();
+    long ImMem = p->GetImage()->GetEstimatedMemorySize();
+    mTotalMem += ImMem;
+
+    GimmickMessage(5,"==> Image in memory = "<<mUnloadQueue.size()<<std::endl);
+    GimmickMessage(5,"==> Total mem       = "<<mTotalMem<<" Ko"<<std::endl);
+
+    //  return;
+
+    while (mTotalMem > mTotalMemMax)
+      {
+       GimmickMessage(5,
+                      "   ! Exceeded max of "
+                      << mTotalMemMax << " Ko : unloading oldest image ... "
+                      << std::endl);
+       if ( mUnloadQueue.size() <= 1 ) 
+         {
+            GimmickMessage(5,
+                           "   Only one image : cannot load AND unload it !!"
+                           <<std::endl);
+           break; 
+           
+         }
+       ImageToLoadPtr unload = mUnloadQueue.remove_top();
+       MultiThreadImageReaderUser* user = unload->GetUser();
+
+       /*
+       if ((user!=0)&&(user!=this)) 
+         {
+           user->GetMultiThreadImageReaderUserMutex().Lock();
+         }
+       */
+
+       std::string filename = unload->GetFilename();
+
+       GimmickMessage(5,"'" << filename << "'" << std::endl);
+       mTotalMem -= unload->GetImage()->GetEstimatedMemorySize();
+
+       GimmickMessage(5," ==> Total mem = "<<mTotalMem<<" Ko "<<std::endl);
+
+       if (user!=0) 
+         {
+           //      std::cout << "unlock..."<<std::endl;
+           //   user->GetMultiThreadImageReaderUserMutex().Unlock();
+           //      std::cout << "event"<<std::endl;
+           user->MultiThreadImageReaderSendEvent
+             (filename,
+              MultiThreadImageReaderUser::ImageUnloaded,
+              0);
+           //      std::cout << "event ok"<<std::endl;
+         }     
+
+       if (unload->Index()>=0)
+         {
+           // GimmickMessage(5,"still in queue"<<std::endl);
+         }
+       unload->Index() = -1;
+
+
+       ImageMapType::iterator it = mImages.find(unload);
+       if (it!=mImages.end())
+         {
+           mImages.erase(it);
+         }
+       //          std::cout << "delete..."<<std::endl;
+       delete unload;
+       //          std::cout << "delete ok."<<std::endl;
+
+      }
+  }
+  //=====================================================================
+
+  //=====================================================================
+  int MultiThreadImageReader::GetMaximalPriority()
+  { 
+    QMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
+    return GetMaximalPriorityWithoutLocking();
+  }
+  //=====================================================================
+
+
+  //=====================================================================
+  int MultiThreadImageReader::GetMaximalPriorityWithoutLocking()
+  { 
+    long max = 0;
+    if (mQueue.size()>0) 
+      {
+       max = mQueue.top()->GetPriority();
+      }
+    if (mUnloadQueue.size()>0)
+      {
+       int max2 = mUnloadQueue.top()->GetPriority();
+       if (max2>max) max=max2;
+      }
+    return max;
+  }
+  //=====================================================================
+
+
+  //=====================================================================
+  //=====================================================================
+  //=====================================================================
+  //=====================================================================
+
+  //=====================================================================
+  void*  ThreadedImageReader::Entry()
+  {
+    //    std::cout << "### Thread "<<GetCurrentId()<<"::Entry()"
+    //               << std::endl;
+
+    mMultiThreadImageReader->MultiThreadImageReaderSendEvent
+      ("",
+       MultiThreadImageReaderUser::ThreadedReaderStarted,
+       0);
+
+    // While was not deleted 
+    while (!isFinished())
+      {
+               //std::cout << "### Thread "<<GetCurrentId()<<" still alive"  << std::endl;
+         
+       // Lock the mutex
+       mMultiThreadImageReader->MultiThreadImageReaderEventLock();
+       //mMutex.Lock();
+       // If image in queue
+       if (mMultiThreadImageReader->mQueue.size()>0)
+         {
+           MultiThreadImageReader::ImageToLoadPtr i = 
+             mMultiThreadImageReader->mQueue.remove_top();
+
+           mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();
+           //mMutex.Unlock();
+
+           
+           //      std::cout << "### Thread "<<GetCurrentId()<<" : reading '"
+           //                << i->GetFilename() << "'" << std::endl;
+           
+           // Do the job
+           vtkImageData* im = Read(i->GetFilename());
+
+           // Store it in the map
+           mMultiThreadImageReader->MultiThreadImageReaderEventLock();
+           //mMutex.Lock();
+           MultiThreadImageReader::ImageToLoad itl(0,i->GetFilename());
+           MultiThreadImageReader::ImageMapType::iterator it = 
+             mMultiThreadImageReader->mImages.find(&itl);
+           MultiThreadImageReader::ImageToLoadPtr 
+             pitl = const_cast<MultiThreadImageReader::ImageToLoadPtr>
+             (it->first);
+           pitl->SetImage(im);
+           mMultiThreadImageReader->SignalImageRead(pitl,true);//i->GetFilename());
+           mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();           //mMutex.Unlock();
+           
+           //      std::cout << "### Thread "<<GetCurrentId()<<" : reading '"
+           //                << i->GetFilename() << "' : DONE" << std::endl;
+           
+         }
+       else 
+         {
+           mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();
+           //mMutex.Unlock();
+           // Wait a little to avoid blocking 
+           Sleep(10);
+         }
+      };
+    //    std::cout << "### Thread "<<GetCurrentId()<<" stopping"
+    //               << std::endl;
+       
+    return 0;
+  }
+  //=====================================================================
+
+  //=====================================================================
+  void ThreadedImageReader::OnExit()
+  {
+    mMultiThreadImageReader->MultiThreadImageReaderSendEvent
+      ("",
+       MultiThreadImageReaderUser::ThreadedReaderStopped,
+       0);
+  }
+  //=====================================================================
+
+  //=====================================================================
+  vtkImageData* ThreadedImageReader::Read(const std::string& filename)
+  {
+    return mReader.ReadImage(filename);
+  }
+  //=====================================================================
+
+} // namespace creaImageIO
diff --git a/src/creaImageIOQMultiThreadImageReader.h b/src/creaImageIOQMultiThreadImageReader.h
new file mode 100644 (file)
index 0000000..bd84033
--- /dev/null
@@ -0,0 +1,259 @@
+#ifndef __creaImageIOQMultiThreadImageReader_h_INCLUDED__
+#define __creaImageIOQMultiThreadImageReader_h_INCLUDED__
+
+#include <creaImageIOSystem.h>
+#include <creaImageIOImageReader.h>
+#include <creaImageIOIndexedHeap.h>
+#include <map>
+#include <deque>
+#include <QMutex>
+#include <queue>
+
+
+
+namespace creaImageIO
+{
+       /**
+       * \ingroup IO
+       */
+  //=====================================================================
+  class ThreadedImageReader;
+  class MultiThreadImageReader;
+  //=====================================================================
+  
+  //=====================================================================
+  class CREAIMAGEIO_EXPORT MultiThreadImageReaderUser
+  {
+  public:
+    friend class ThreadedImageReader;
+    friend class MultiThreadImageReader;
+
+    MultiThreadImageReaderUser() {}
+    virtual ~MultiThreadImageReaderUser() {}
+
+    typedef enum 
+      {
+       ThreadedReaderStarted,
+       ThreadedReaderStopped,
+       ImageLoaded,
+       ImageUnloaded,
+       Error
+      }
+      EventType;
+    /// The virtual method to overload by MultiThreadImageReader users
+      /// It is called when an image has been loaded or unloaded 
+      /// Provides :
+      /// * The image file name which was requested 
+      /// * The type of event 
+      /// * If type==ImageLoaded the image pointer, else NULL pointer 
+    virtual void OnMultiThreadImageReaderEvent( const std::string& filename,
+                                               EventType type,
+                                               vtkImageData* image) 
+    {}
+    inline void MultiThreadImageReaderEventLock() 
+    { mMultiThreadImageReaderUserMutex.lock(); }
+    inline void MultiThreadImageReaderEventUnlock() 
+    { mMultiThreadImageReaderUserMutex.unlock(); }
+    inline QMutex* GetMultiThreadImageReaderUserMutex() 
+    { return &mMultiThreadImageReaderUserMutex; }
+  private:
+    /// 
+    void MultiThreadImageReaderSendEvent( const std::string& filename,
+                                         EventType type,
+                                         vtkImageData* image);
+    QMutex mMultiThreadImageReaderUserMutex;
+  };
+  //=====================================================================
+
+  //=====================================================================
+  /// 
+  /// TAKE CARE : For the moment it only supports a **SINGLE USER** 
+
+   ///Class that allows parallel lectures of several images
+  class MultiThreadImageReader : public MultiThreadImageReaderUser
+  {
+  public:
+    friend class ThreadedImageReader;
+
+    /// Ctor with the number of threads to use
+    MultiThreadImageReader(int number_of_threads = 1);
+    /// Dtor 
+    ~MultiThreadImageReader();
+
+    /// Starts the reader = create the threads which start to check 
+    /// periodically the queue of requested images to read
+    bool Start();
+    /// Stops the reader = stops the threads and delete the images loaded
+    void Stop();
+
+    /// Request the image "filename" with a given priority 
+    /// When the image is ready (or an error occurred) 
+    /// The observer's callback is invoked 
+    void Request( MultiThreadImageReaderUser* user,
+                 const std::string& filename, 
+                 int priority );
+    
+    /// Request the image "filename" immediately 
+       /// Blocks until image loaded
+    /// (no user callback but image returned)
+    vtkImageData* GetImage(const std::string& filename);
+
+    /// 
+    int GetMaximalPriority(); 
+    
+    ///
+    void OnMultiThreadImageReaderEvent( const std::string& filename,
+                                       EventType type,
+                                       vtkImageData* image);
+   
+    /// Function to read attributes for a file 
+       void getAttributes(const std::string filename, std::map <std::string , std::string> &infos, std::vector<std::string> i_attr);
+
+  protected:
+         bool mDone;
+    int GetMaximalPriorityWithoutLocking();
+    ///Class that represents an image to be loaded
+    class ImageToLoad
+    {
+    public:
+      ImageToLoad( MultiThreadImageReaderUser* user,
+                  const std::string& filename, 
+                  int prio=0) 
+       : mUser(user),
+         mFilename(filename), 
+         mPriority(prio), 
+         mIndex(-1), 
+         mUnloadIndex(-1), 
+         mImage(0)
+      {}
+      ~ImageToLoad()
+      {
+       if (mImage>0) 
+         {
+           //      std::cout << "Refs = "<<mImage->GetReferenceCount()<<std::endl;
+           mImage->Delete();
+         }
+      }
+      MultiThreadImageReaderUser* GetUser() const { return mUser; }
+      void SetUser( MultiThreadImageReaderUser* u ) { mUser = u; }
+      const std::string& GetFilename() const { return mFilename; }
+      int GetPriority() const { return mPriority; }
+      void SetPriority(int p) { mPriority=p; }
+      int& Index() { return mIndex; }
+      int& UnloadIndex() { return mUnloadIndex; }
+      vtkImageData* GetImage() const { return mImage; }
+      void SetImage( vtkImageData* i ) { mImage=i; }
+
+         std::map<std::string, std::string> getAttributes(const std::vector<std::string> i_attr);
+    private:
+      MultiThreadImageReaderUser* mUser;
+      std::string mFilename;
+      int mPriority;
+      int mIndex;
+      int mUnloadIndex;
+      vtkImageData* mImage;
+    };
+    // 
+
+    /// Type of pointer on an ImageToLoad struct
+    typedef ImageToLoad* ImageToLoadPtr;
+
+    /// ImageToLoadPtr comparator on priority (for image queue)
+    struct ImageToLoadPtrPriorityComparator
+    {
+      bool operator() (ImageToLoadPtr const & a, ImageToLoadPtr const & b)
+       const 
+      {
+       return ( a->GetPriority() > b->GetPriority() );
+      }
+    };
+    /// ImageToLoadPtr comparator on inverse priority (for image to unload queue)
+    struct ImageToLoadPtrInversePriorityComparator
+    {
+      bool operator() (ImageToLoadPtr const & a, ImageToLoadPtr const & b)
+       const 
+      {
+       return ( a->GetPriority() < b->GetPriority() );
+      }
+    };
+
+
+    /// ImageToLoadPtr comparator on filename (for image map)
+    struct ImageToLoadPtrFilenameComparator
+    {
+      bool operator() (ImageToLoadPtr const & a, ImageToLoadPtr const & b)
+       const 
+      {
+       return ( a->GetFilename() < b->GetFilename() );
+      }
+    };
+
+    /// ImageToLoadPtr indexer for image queue
+    struct ImageToLoadPtrIndexer
+    {
+      int& operator()(ImageToLoadPtr & t) const { return t->Index(); }
+    };
+    /// ImageToLoadPtr indexer for to unload image queue
+    struct ImageToUnloadPtrIndexer
+    {
+      int& operator()(ImageToLoadPtr & t) const { return t->UnloadIndex(); }
+    };
+
+    /// The callback from threaded readers when an image is read
+    void SignalImageRead(ImageToLoadPtr p, bool purge);
+  
+    /// The type of map of images 
+    typedef std::map<ImageToLoadPtr,vtkImageData*,
+                    ImageToLoadPtrFilenameComparator> ImageMapType;
+    /// The map of images
+    ImageMapType mImages;
+    /// Comparator for the image to load queue
+    ImageToLoadPtrPriorityComparator mComparator;
+    /// Indexer for the image to load queue 
+    ImageToLoadPtrIndexer mIndexer;
+    /// The image to load priority queue
+    IndexedHeap<ImageToLoadPtr,
+               ImageToLoadPtrPriorityComparator,
+               ImageToLoadPtrIndexer> mQueue;
+
+    /// The type of list of threaded readers
+       typedef std::vector<boost::shared_ptr<ThreadedImageReader> > ThreadedImageReaderListType;
+       //typedef std::vector<ThreadedImageReader* > ThreadedImageReaderListType;
+    ThreadedImageReaderListType mThreadedImageReaderList;
+    /// The number of currently running threaded readers
+    int mNumberOfThreadedReadersRunning;
+    /// The mutex used to access safely internal data from any thread
+    /// LG : Removed ! We now use the embedded mutex in User from which 
+    /// we inherit...
+    //  wxMutex mMutex;
+
+    /// For GetImage : the filename requested
+    std::string mRequestedFilename;
+    /// For GetImage : the image requested
+    vtkImageData* mRequestedImage;
+
+    /// If number of threads == 0 then uses an internal non-threaded reader
+    ImageReader* mReader;
+
+    /// The type of list of images loaded 
+    /// used to unload oldest image when memory limit exceeded
+   /// The image to unload priority queue
+    IndexedHeap<ImageToLoadPtr,
+               ImageToLoadPtrInversePriorityComparator,
+               ImageToUnloadPtrIndexer> mUnloadQueue;
+
+    void UpdateUnloadPriority(ImageToLoadPtr p, int priority);
+    long mTotalMem;
+    long mTotalMemMax;
+
+
+  }; // class MultiThreadImageReader
+  //=====================================================================
+
+
+
+} // namespace creaImageIO
+
+
+
+#endif // #ifndef __creaImageIOQMultiThreadImageReader_h_INCLUDED__