--- /dev/null
+#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
--- /dev/null
+#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__