/* # --------------------------------------------------------------------- # # Copyright (c) CREATIS (Centre de Recherche en Acquisition et Traitement de l'Image # pour la Santé) # Authors : Eduardo Davila, Frederic Cervenansky, Claire Mouton # Previous Authors : Laurent Guigues, Jean-Pierre Roux # CreaTools website : www.creatis.insa-lyon.fr/site/fr/creatools_accueil # # This software is governed by the CeCILL-B license under French law and # abiding by the rules of distribution of free software. You can use, # modify and/ or redistribute the software under the terms of the CeCILL-B # license as circulated by CEA, CNRS and INRIA at the following URL # http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html # or in the file LICENSE.txt. # # As a counterpart to the access to the source code and rights to copy, # modify and redistribute granted by the license, users are provided only # with a limited warranty and the software's author, the holder of the # economic rights, and the successive licensors have only limited # liability. # # The fact that you are presently reading this means that you have had # knowledge of the CeCILL-B license and that you accept its terms. # ------------------------------------------------------------------------ */ #include #include #include #include #include #ifdef _DEBUG #define new DEBUG_NEW #endif namespace creaImageIO { //===================================================================== void MultiThreadImageReaderUser::MultiThreadImageReaderSendEvent ( const std::string& filename, EventType type, vtkImageData* image) { wxMutexLocker lock(mMultiThreadImageReaderUserMutex); this->OnMultiThreadImageReaderEvent(filename,type,image); } //===================================================================== //===================================================================== class ThreadedImageReader: public wxThread { public: ThreadedImageReader(MultiThreadImageReader* tir) : mMultiThreadImageReader(tir) {} void* Entry(); void OnExit(); vtkImageData* Read(const std::string& filename); struct deleter { void operator()(ThreadedImageReader* p) { p->Delete(); } }; 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 <<" )"< t(new ThreadedImageReader(this), ThreadedImageReader::deleter()); mThreadedImageReaderList.push_back(t); std::cout << " ===> Thread "< 0) return true; ThreadedImageReaderListType::iterator i; for (i =mThreadedImageReaderList.begin(); i!=mThreadedImageReaderList.end(); i++) { (*i)->Create(); if ( (*i)->Run() != wxTHREAD_NO_ERROR ) { std::cout << "ERROR starting a thread"<< std::endl; return false; } else { std::cout << " ===> Thread "<<(*i)->GetCurrentId() <<" successfully created"<< std::endl; } } wxMutexLocker locker(GetMultiThreadImageReaderUserMutex()); // std::cout << "EO Start : #Threads running = " // << mNumberOfThreadedReadersRunning< Thread "<<(*i)->GetCurrentId() <<" successfully stopped"<< std::endl; if((*i)->IsAlive()) {(*i)->Pause(); (*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..."<first; } mImages.clear(); mDone = true; } //===================================================================== //===================================================================== MultiThreadImageReader::~MultiThreadImageReader() { // std::cout << "#### MultiThreadImageReader::~MultiThreadImageReader()" // <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 &infos,std::vector i_attr) { mReader->getAttributes(filename, infos, i_attr); } //===================================================================== void MultiThreadImageReader::Request( MultiThreadImageReaderUser* user, const std::string& filename, int priority ) { wxMutexLocker 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(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(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('"<(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(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..."<GetFilename()<<"' read"<GetImage()->UpdateInformation(); p->GetImage()->PropagateUpdateExtent(); long ImMem = p->GetImage()->GetEstimatedMemorySize(); mTotalMem += ImMem; GimmickMessage(5,"==> Image in memory = "< Total mem = "< 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 !!" <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 = "<GetMultiThreadImageReaderUserMutex().Unlock(); // std::cout << "event"<MultiThreadImageReaderSendEvent (filename, MultiThreadImageReaderUser::ImageUnloaded, 0); // std::cout << "event ok"<Index()>=0) { // GimmickMessage(5,"still in queue"<Index() = -1; ImageMapType::iterator it = mImages.find(unload); if (it!=mImages.end()) { mImages.erase(it); } // std::cout << "delete..."<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 "<MultiThreadImageReaderSendEvent ("", MultiThreadImageReaderUser::ThreadedReaderStarted, 0); // While was not deleted while (!TestDestroy()) { //std::cout << "### Thread "<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 "<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 (it->first); pitl->SetImage(im); mMultiThreadImageReader->SignalImageRead(pitl,true);//i->GetFilename()); mMultiThreadImageReader->MultiThreadImageReaderEventUnlock(); //mMutex.Unlock(); // std::cout << "### Thread "<GetFilename() << "' : DONE" << std::endl; } else { mMultiThreadImageReader->MultiThreadImageReaderEventUnlock(); //mMutex.Unlock(); // Wait a little to avoid blocking Sleep(10); } }; // std::cout << "### Thread "<MultiThreadImageReaderSendEvent ("", MultiThreadImageReaderUser::ThreadedReaderStopped, 0); } //===================================================================== //===================================================================== vtkImageData* ThreadedImageReader::Read(const std::string& filename) { return mReader.ReadImage(filename); } //===================================================================== } // namespace creaImageIO