2 # ---------------------------------------------------------------------
4 # Copyright (c) CREATIS (Centre de Recherche en Acquisition et Traitement de l'Image
6 # Authors : Eduardo Davila, Frederic Cervenansky, Claire Mouton
7 # Previous Authors : Laurent Guigues, Jean-Pierre Roux
8 # CreaTools website : www.creatis.insa-lyon.fr/site/fr/creatools_accueil
10 # This software is governed by the CeCILL-B license under French law and
11 # abiding by the rules of distribution of free software. You can use,
12 # modify and/ or redistribute the software under the terms of the CeCILL-B
13 # license as circulated by CEA, CNRS and INRIA at the following URL
14 # http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
15 # or in the file LICENSE.txt.
17 # As a counterpart to the access to the source code and rights to copy,
18 # modify and redistribute granted by the license, users are provided only
19 # with a limited warranty and the software's author, the holder of the
20 # economic rights, and the successive licensors have only limited
23 # The fact that you are presently reading this means that you have had
24 # knowledge of the CeCILL-B license and that you accept its terms.
25 # ------------------------------------------------------------------------
29 #include <vtkVersionMacros.h>
30 #include <creaImageIOMultiThreadImageReader.h>
31 #include <creaImageIOImageReader.h>
33 #include <creaImageIOSystem.h>
35 #include <creaImageIODicomImageReader.h>
38 #include <creaImageIOGimmick.h>
45 //=====================================================================
46 void MultiThreadImageReaderUser::MultiThreadImageReaderSendEvent
47 ( const std::string& filename,
51 wxMutexLocker lock(mMultiThreadImageReaderUserMutex);
52 this->OnMultiThreadImageReaderEvent(filename,type,image);
54 //=====================================================================
59 void Delete() { printf("EED wxThreadEED2::Delete() \n"); }
60 int Run() { printf("EED wxThreadEED2::Run() \n"); return 0;}
61 void Pause() { printf("EED wxThreadEED2::Pause() \n"); }
62 void Create() { printf("EED wxThreadEED2::Create() \n"); }
63 bool IsAlive() { printf("EED wxThreadEED2::IsAlive() \n"); return false; }
64 bool TestDestroy() { printf("EED wxThreadEED2::TestDestroy() \n"); return false; }
65 int GetCurrentId() { printf("EED wxThreadEED2::GetCurrentId() \n"); return -999; }
68 //=====================================================================
70 // class ThreadedImageReader: public wxThread
71 class ThreadedImageReader: public wxThreadEED2
74 ThreadedImageReader(MultiThreadImageReader* tir) :
75 mMultiThreadImageReader(tir)
79 vtkImageData* Read(const std::string& filename);
82 void operator()(ThreadedImageReader* p)
87 friend struct deleter;
91 MultiThreadImageReader* mMultiThreadImageReader;
94 //=====================================================================
97 //=====================================================================
98 MultiThreadImageReader::MultiThreadImageReader(int number_of_threads)
99 : //mDoNotSignal(false),
102 mTotalMemMax(1000000)
104 // std::cout << "#### MultiThreadImageReader::MultiThreadImageReader("
105 // << " #threads= " << number_of_threads <<" )"<<std::endl;
108 // Create the threads
110 for (int i=0; i<number_of_threads; i++)
112 //ThreadedImageReader* t = new ThreadedImageReader(this);
113 boost::shared_ptr<ThreadedImageReader> t(new ThreadedImageReader(this), ThreadedImageReader::deleter());
114 mThreadedImageReaderList.push_back(t);
115 std::cout << " ===> Thread "<<i <<" successfully added"<< std::endl;
117 mNumberOfThreadedReadersRunning = 0;
119 mQueue.set(mComparator);
120 mQueue.set(mIndexer);
122 // no thread : alloc self reader
123 // if (number_of_threads==0)
125 mReader = new ImageReader();
128 //=====================================================================
131 //=====================================================================
132 bool MultiThreadImageReader::Start()
134 // std::cout << "#### MultiThreadImageReader::Start()"
136 if (mNumberOfThreadedReadersRunning > 0) return true;
138 ThreadedImageReaderListType::iterator i;
139 for (i =mThreadedImageReaderList.begin();
140 i!=mThreadedImageReaderList.end();
144 if ( (*i)->Run() != wxTHREAD_NO_ERROR )
146 std::cout << "ERROR starting a thread"<< std::endl;
149 std::cout << " ===> Thread "<<(*i)->GetCurrentId()
150 <<" successfully created"<< std::endl;
153 wxMutexLocker locker(GetMultiThreadImageReaderUserMutex());
154 // std::cout << "EO Start : #Threads running = "
155 // << mNumberOfThreadedReadersRunning<<std::endl;
158 //=====================================================================
160 //=====================================================================
161 void MultiThreadImageReader::Stop()
163 // std::cout << "#### MultiThreadImageReader::Stop()"
165 // std::cout << "Sending stop order to the threads..."<<std::endl;
169 ThreadedImageReaderListType::iterator i;
170 for (i =mThreadedImageReaderList.begin();
171 i!=mThreadedImageReaderList.end();
174 std::cout << " ===> Thread "<<(*i)->GetCurrentId()
175 <<" successfully stopped"<< std::endl;
183 mThreadedImageReaderList.clear();
184 // Wait a little to be sure that all threads have stopped
185 // A better way to do this ?
186 // wxMilliSleep(1000);
187 // New method : the threads generate a stop event when they have finished
188 // We wait until all threads have stopped
189 // std::cout << "Waiting for stop signals..."<<std::endl;
196 wxMutexLocker locker(GetMultiThreadImageReaderUserMutex());
197 // std::cout << "#Threads running = "
198 // << mNumberOfThreadedReadersRunning<<std::endl;
199 // Break if all readers have stopped
200 if (mNumberOfThreadedReadersRunning <= 0)
207 // std::cout << "All threads stopped : OK "<<std::endl;
215 //=====================================================================
218 void MultiThreadImageReader::CleanMImagesMap()
220 ImageMapType::iterator j;
221 for (j=mImages.begin(); j!=mImages.end(); ++j)
228 //=====================================================================
229 MultiThreadImageReader::~MultiThreadImageReader()
231 // std::cout << "#### MultiThreadImageReader::~MultiThreadImageReader()"
234 if (mReader) delete mReader;
235 mThreadedImageReaderList.clear();
240 ImageMapType::iterator it;
241 for (it=mImages.begin() ; it!=mImages.end(); it++)
243 printf("MultiThreadImageReader::~MultiThreadImageReader %s ", it.first->GetFilename() );
248 //=====================================================================
250 //=====================================================================
251 void MultiThreadImageReader::UpdateUnloadPriority(ImageToLoadPtr p,
254 // not in unload queue : ciao
255 if (p->UnloadIndex()<0) return;
256 int old_prio = p->GetPriority();
257 if (priority > old_prio)
259 p->SetPriority(priority);
260 mUnloadQueue.downsort(p->UnloadIndex());
262 else if ( old_prio > priority )
264 p->SetPriority(priority);
265 mUnloadQueue.upsort(p->UnloadIndex());
268 //=====================================================================
269 // function to read attributes for a file
270 void MultiThreadImageReader::getAttributes(const std::string filename,
271 std::map <std::string , std::string> &infos,std::vector<std::string> i_attr)
273 mReader->getAttributes(filename, infos, i_attr);
276 //=====================================================================
277 void MultiThreadImageReader::Request( MultiThreadImageReaderUser* user,
278 const std::string& filename,
281 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
283 if (mNumberOfThreadedReadersRunning==0)
284 // if (mThreadedImageReaderList.size()==0)
286 // no detached reader : use self reader
287 ImageToLoad itl(user,filename);
288 ImageMapType::iterator i = mImages.find(&itl);
289 if (i!=mImages.end())
291 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
293 if (pitl->GetImage() != 0)
297 UpdateUnloadPriority(pitl,priority);
298 SignalImageRead(pitl,false);
299 return; // pitl->GetImage();
302 ImageToLoadPtr pitl = new ImageToLoad(user,filename,0);
304 pitl->SetImage(mReader->ReadImage(filename));
305 UpdateUnloadPriority(pitl,priority);
306 SignalImageRead(pitl,true);
307 // return pitl->GetImage();
311 ImageToLoad itl(user,filename);
312 ImageMapType::iterator i = mImages.find(&itl);
313 if (i!=mImages.end())
316 if (i->first->GetImage() != 0)
318 // Already read : ok :signal the user
319 UpdateUnloadPriority(i->first,priority);
320 SignalImageRead(i->first,false);
323 /// Already requested : change the priority
324 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
325 pitl->SetPriority(priority);
327 if (pitl->Index()>=0)
330 mQueue.upsort(pitl->Index());
332 // Not read but not in queue = being read = ok
340 // Never requested before or unloaded
341 ImageToLoadPtr pitl = new ImageToLoad(user,filename,priority);
346 //=====================================================================
348 //=====================================================================
349 void MultiThreadImageReader::OnMultiThreadImageReaderEvent
350 (const std::string& filename,
351 MultiThreadImageReaderUser::EventType e,
354 if ((e==MultiThreadImageReaderUser::ImageLoaded) &&
355 (filename == mRequestedFilename))
357 mRequestedImage = image;
359 else if (e==MultiThreadImageReaderUser::ThreadedReaderStarted)
361 mNumberOfThreadedReadersRunning++;
362 // std::cout << "#TR=" << mNumberOfThreadedReadersRunning << std::endl;
364 else if (e==MultiThreadImageReaderUser::ThreadedReaderStopped)
367 mNumberOfThreadedReadersRunning--;
368 // std::cout << "#TR=" << mNumberOfThreadedReadersRunning << std::endl;
371 //=====================================================================
373 //=====================================================================
374 vtkImageData* MultiThreadImageReader::GetImage(const std::string& filename)
379 // wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
381 // std::cout << "** MultiThreadImageReader::GetImage('"<<filename
385 // if (mNumberOfThreadedReadersRunning==0)
386 // if (mThreadedImageReaderList.size()==0)
389 ImageToLoad itl(this,filename);
390 ImageMapType::iterator i = mImages.find(&itl);
391 if (i!=mImages.end())
393 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
395 if (pitl->GetImage() != NULL)
398 UpdateUnloadPriority( pitl, GetMaximalPriorityWithoutLocking()+1 );
399 return pitl->GetImage();
400 } // if pitl->GetImage()
403 ImageToLoadPtr pitl = new ImageToLoad(this,filename,0);
404 mImages[pitl] = NULL;
405 pitl->SetImage( mReader->ReadImage(filename) );
406 UpdateUnloadPriority( pitl, GetMaximalPriorityWithoutLocking()+1 );
407 return pitl->GetImage();
411 mRequestedFilename = filename;
413 ImageToLoad itl(this,filename);
414 ImageMapType::iterator i = mImages.find(&itl);
415 if (i!=mImages.end())
417 // Already inserted in queue
418 if (i->first->GetImage() != 0)
420 // Already read : ok : return it
421 return i->first->GetImage();
423 /// Already requested : change the priority
424 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
425 pitl->SetPriority( GetMaximalPriorityWithoutLocking() + 1 );
426 pitl->SetUser( this );
428 if (pitl->Index()>=0)
431 mQueue.upsort(pitl->Index());
433 // Not read but not in queue = being read = ok
436 pitl->SetUser( this );
442 // Never requested before or unloaded
443 ImageToLoadPtr pitl =
444 new ImageToLoad(this,filename,
445 GetMaximalPriorityWithoutLocking() + 1);
453 // std::cout << "Waiting..."<<std::endl;
456 // Waiting that it is read
460 // std::cout << n++ << std::endl;
464 // wxMutexLocker lock(mMutex);
465 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex());
466 if (mRequestedImage!=0)
468 return mRequestedImage;
478 //=====================================================================
480 //=====================================================================
481 void MultiThreadImageReader::SignalImageRead(ImageToLoadPtr p,
485 // std::cout << "MultiThreadImageReader::SignalImageRead" <<std::endl;
486 // std::cout << "this="<<this <<std::endl;
487 // std::cout << "user="<<p->GetUser() <<std::endl;
489 if ( p->GetUser() == this )
491 GetMultiThreadImageReaderUserMutex().Unlock();
494 p->GetUser()->MultiThreadImageReaderSendEvent
496 MultiThreadImageReaderUser::ImageLoaded,
500 AN ATTEMPT TO UNLOAD OLDEST IMAGE IF EXCEEDED A CERTAIN MEMORY QUOTA
504 GimmickMessage(5,"Image '"<<p->GetFilename()<<"' read"<<std::endl);
506 // wxMutexLocker lock(GetMultiThreadImageReaderUserMutex());
508 mUnloadQueue.insert(p);
511 //EED 2017-01-01 Migration VTK7
512 #if VTK_MAJOR_VERSION <= 5
513 p->GetImage()->UpdateInformation();
514 p->GetImage()->PropagateUpdateExtent();
515 long ImMem = p->GetImage()->GetEstimatedMemorySize();
519 p->GetImage()->GetExtent(ext);
520 dim[0] = ext[1]-ext[0]+1;
521 dim[1] = ext[3]-ext[2]+1;
522 dim[2] = ext[5]-ext[4]+1;
523 long ImMem = dim[0]*dim[1]*dim[2]*p->GetImage()->GetScalarSize();;
527 GimmickMessage(5,"==> Image in memory = "<<mUnloadQueue.size()<<std::endl);
528 GimmickMessage(5,"==> Total mem = "<<mTotalMem<<" Ko"<<std::endl);
532 while (mTotalMem > mTotalMemMax)
535 " ! Exceeded max of "
536 << mTotalMemMax << " Ko : unloading oldest image ... "
538 if ( mUnloadQueue.size() <= 1 )
541 " Only one image : cannot load AND unload it !!"
546 ImageToLoadPtr unload = mUnloadQueue.remove_top();
547 MultiThreadImageReaderUser* user = unload->GetUser();
550 if ((user!=0)&&(user!=this))
552 user->GetMultiThreadImageReaderUserMutex().Lock();
556 std::string filename = unload->GetFilename();
558 GimmickMessage(5,"'" << filename << "'" << std::endl);
560 //EED 2017-01-01 Migration VTK7
561 #if VTK_MAJOR_VERSION <= 5
562 mTotalMem -= unload->GetImage()->GetEstimatedMemorySize();
566 unload->GetImage()->GetExtent(ext);
567 dim[0] = ext[1]-ext[0]+1;
568 dim[1] = ext[3]-ext[2]+1;
569 dim[2] = ext[5]-ext[4]+1;
570 mTotalMem -= dim[0]*dim[1]*dim[2]*unload->GetImage()->GetScalarSize();
573 GimmickMessage(5," ==> Total mem = "<<mTotalMem<<" Ko "<<std::endl);
577 // std::cout << "unlock..."<<std::endl;
578 // user->GetMultiThreadImageReaderUserMutex().Unlock();
579 // std::cout << "event"<<std::endl;
580 user->MultiThreadImageReaderSendEvent
582 MultiThreadImageReaderUser::ImageUnloaded,
584 // std::cout << "event ok"<<std::endl;
587 if (unload->Index()>=0)
589 // GimmickMessage(5,"still in queue"<<std::endl);
591 unload->Index() = -1;
594 ImageMapType::iterator it = mImages.find(unload);
595 if (it!=mImages.end())
599 // std::cout << "delete..."<<std::endl;
601 // std::cout << "delete ok."<<std::endl;
605 //=====================================================================
607 //=====================================================================
608 int MultiThreadImageReader::GetMaximalPriority()
610 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
611 return GetMaximalPriorityWithoutLocking();
613 //=====================================================================
616 //=====================================================================
617 int MultiThreadImageReader::GetMaximalPriorityWithoutLocking()
622 max = mQueue.top()->GetPriority();
624 if (mUnloadQueue.size()>0)
626 int max2 = mUnloadQueue.top()->GetPriority();
627 if (max2>max) max=max2;
631 //=====================================================================
634 //=====================================================================
635 //=====================================================================
636 //=====================================================================
637 //=====================================================================
639 //=====================================================================
640 void* ThreadedImageReader::Entry()
642 // std::cout << "### Thread "<<GetCurrentId()<<"::Entry()"
645 mMultiThreadImageReader->MultiThreadImageReaderSendEvent
647 MultiThreadImageReaderUser::ThreadedReaderStarted,
650 // While was not deleted
651 while (!TestDestroy())
653 //std::cout << "### Thread "<<GetCurrentId()<<" still alive" << std::endl;
656 mMultiThreadImageReader->MultiThreadImageReaderEventLock();
659 if (mMultiThreadImageReader->mQueue.size()>0)
661 MultiThreadImageReader::ImageToLoadPtr i =
662 mMultiThreadImageReader->mQueue.remove_top();
664 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();
668 // std::cout << "### Thread "<<GetCurrentId()<<" : reading '"
669 // << i->GetFilename() << "'" << std::endl;
672 vtkImageData* im = Read(i->GetFilename());
674 // Store it in the map
675 mMultiThreadImageReader->MultiThreadImageReaderEventLock();
677 MultiThreadImageReader::ImageToLoad itl(0,i->GetFilename());
678 MultiThreadImageReader::ImageMapType::iterator it =
679 mMultiThreadImageReader->mImages.find(&itl);
680 MultiThreadImageReader::ImageToLoadPtr
681 pitl = const_cast<MultiThreadImageReader::ImageToLoadPtr>
684 mMultiThreadImageReader->SignalImageRead(pitl,true);//i->GetFilename());
685 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock(); //mMutex.Unlock();
687 // std::cout << "### Thread "<<GetCurrentId()<<" : reading '"
688 // << i->GetFilename() << "' : DONE" << std::endl;
691 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();
693 // Wait a little to avoid blocking
697 // std::cout << "### Thread "<<GetCurrentId()<<" stopping"
702 //=====================================================================
704 //=====================================================================
705 void ThreadedImageReader::OnExit()
707 mMultiThreadImageReader->MultiThreadImageReaderSendEvent
709 MultiThreadImageReaderUser::ThreadedReaderStopped,
712 //=====================================================================
714 //=====================================================================
715 vtkImageData* ThreadedImageReader::Read(const std::string& filename)
717 return mReader.ReadImage(filename);
719 //=====================================================================
721 } // namespace creaImageIO