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 <creaImageIOMultiThreadImageReader.h>
30 #include <creaImageIOImageReader.h>
32 #include <creaImageIOSystem.h>
34 #include <creaImageIODicomImageReader.h>
37 #include <creaImageIOGimmick.h>
44 //=====================================================================
45 void MultiThreadImageReaderUser::MultiThreadImageReaderSendEvent
46 ( const std::string& filename,
50 wxMutexLocker lock(mMultiThreadImageReaderUserMutex);
51 this->OnMultiThreadImageReaderEvent(filename,type,image);
53 //=====================================================================
58 void Delete() { printf("EED wxThreadEED2::Delete() \n"); }
59 int Run() { printf("EED wxThreadEED2::Run() \n"); return 0;}
60 void Pause() { printf("EED wxThreadEED2::Pause() \n"); }
61 void Create() { printf("EED wxThreadEED2::Create() \n"); }
62 bool IsAlive() { printf("EED wxThreadEED2::IsAlive() \n"); return false; }
63 bool TestDestroy() { printf("EED wxThreadEED2::TestDestroy() \n"); return false; }
64 int GetCurrentId() { printf("EED wxThreadEED2::GetCurrentId() \n"); return -999; }
67 //=====================================================================
69 // class ThreadedImageReader: public wxThread
70 class ThreadedImageReader: public wxThreadEED2
73 ThreadedImageReader(MultiThreadImageReader* tir) :
74 mMultiThreadImageReader(tir)
78 vtkImageData* Read(const std::string& filename);
81 void operator()(ThreadedImageReader* p)
86 friend struct deleter;
90 MultiThreadImageReader* mMultiThreadImageReader;
93 //=====================================================================
96 //=====================================================================
97 MultiThreadImageReader::MultiThreadImageReader(int number_of_threads)
98 : //mDoNotSignal(false),
101 mTotalMemMax(1000000)
103 // std::cout << "#### MultiThreadImageReader::MultiThreadImageReader("
104 // << " #threads= " << number_of_threads <<" )"<<std::endl;
107 // Create the threads
109 for (int i=0; i<number_of_threads; i++)
111 //ThreadedImageReader* t = new ThreadedImageReader(this);
112 boost::shared_ptr<ThreadedImageReader> t(new ThreadedImageReader(this), ThreadedImageReader::deleter());
113 mThreadedImageReaderList.push_back(t);
114 std::cout << " ===> Thread "<<i <<" successfully added"<< std::endl;
116 mNumberOfThreadedReadersRunning = 0;
118 mQueue.set(mComparator);
119 mQueue.set(mIndexer);
121 // no thread : alloc self reader
122 // if (number_of_threads==0)
124 mReader = new ImageReader();
127 //=====================================================================
130 //=====================================================================
131 bool MultiThreadImageReader::Start()
133 // std::cout << "#### MultiThreadImageReader::Start()"
135 if (mNumberOfThreadedReadersRunning > 0) return true;
137 ThreadedImageReaderListType::iterator i;
138 for (i =mThreadedImageReaderList.begin();
139 i!=mThreadedImageReaderList.end();
143 if ( (*i)->Run() != wxTHREAD_NO_ERROR )
145 std::cout << "ERROR starting a thread"<< std::endl;
148 std::cout << " ===> Thread "<<(*i)->GetCurrentId()
149 <<" successfully created"<< std::endl;
152 wxMutexLocker locker(GetMultiThreadImageReaderUserMutex());
153 // std::cout << "EO Start : #Threads running = "
154 // << mNumberOfThreadedReadersRunning<<std::endl;
157 //=====================================================================
159 //=====================================================================
160 void MultiThreadImageReader::Stop()
162 // std::cout << "#### MultiThreadImageReader::Stop()"
164 // std::cout << "Sending stop order to the threads..."<<std::endl;
168 ThreadedImageReaderListType::iterator i;
169 for (i =mThreadedImageReaderList.begin();
170 i!=mThreadedImageReaderList.end();
173 std::cout << " ===> Thread "<<(*i)->GetCurrentId()
174 <<" successfully stopped"<< std::endl;
182 mThreadedImageReaderList.clear();
183 // Wait a little to be sure that all threads have stopped
184 // A better way to do this ?
185 // wxMilliSleep(1000);
186 // New method : the threads generate a stop event when they have finished
187 // We wait until all threads have stopped
188 // std::cout << "Waiting for stop signals..."<<std::endl;
195 wxMutexLocker locker(GetMultiThreadImageReaderUserMutex());
196 // std::cout << "#Threads running = "
197 // << mNumberOfThreadedReadersRunning<<std::endl;
198 // Break if all readers have stopped
199 if (mNumberOfThreadedReadersRunning <= 0)
206 // std::cout << "All threads stopped : OK "<<std::endl;
214 //=====================================================================
217 void MultiThreadImageReader::CleanMImagesMap()
219 ImageMapType::iterator j;
220 for (j=mImages.begin(); j!=mImages.end(); ++j)
227 //=====================================================================
228 MultiThreadImageReader::~MultiThreadImageReader()
230 // std::cout << "#### MultiThreadImageReader::~MultiThreadImageReader()"
233 if (mReader) delete mReader;
234 mThreadedImageReaderList.clear();
239 ImageMapType::iterator it;
240 for (it=mImages.begin() ; it!=mImages.end(); it++)
242 printf("MultiThreadImageReader::~MultiThreadImageReader %s ", it.first->GetFilename() );
247 //=====================================================================
249 //=====================================================================
250 void MultiThreadImageReader::UpdateUnloadPriority(ImageToLoadPtr p,
253 // not in unload queue : ciao
254 if (p->UnloadIndex()<0) return;
255 int old_prio = p->GetPriority();
256 if (priority > old_prio)
258 p->SetPriority(priority);
259 mUnloadQueue.downsort(p->UnloadIndex());
261 else if ( old_prio > priority )
263 p->SetPriority(priority);
264 mUnloadQueue.upsort(p->UnloadIndex());
267 //=====================================================================
268 // function to read attributes for a file
269 void MultiThreadImageReader::getAttributes(const std::string filename,
270 std::map <std::string , std::string> &infos,std::vector<std::string> i_attr)
272 mReader->getAttributes(filename, infos, i_attr);
275 //=====================================================================
276 void MultiThreadImageReader::Request( MultiThreadImageReaderUser* user,
277 const std::string& filename,
280 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
282 if (mNumberOfThreadedReadersRunning==0)
283 // if (mThreadedImageReaderList.size()==0)
285 // no detached reader : use self reader
286 ImageToLoad itl(user,filename);
287 ImageMapType::iterator i = mImages.find(&itl);
288 if (i!=mImages.end())
290 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
292 if (pitl->GetImage() != 0)
296 UpdateUnloadPriority(pitl,priority);
297 SignalImageRead(pitl,false);
298 return; // pitl->GetImage();
301 ImageToLoadPtr pitl = new ImageToLoad(user,filename,0);
303 pitl->SetImage(mReader->ReadImage(filename));
304 UpdateUnloadPriority(pitl,priority);
305 SignalImageRead(pitl,true);
306 // return pitl->GetImage();
310 ImageToLoad itl(user,filename);
311 ImageMapType::iterator i = mImages.find(&itl);
312 if (i!=mImages.end())
315 if (i->first->GetImage() != 0)
317 // Already read : ok :signal the user
318 UpdateUnloadPriority(i->first,priority);
319 SignalImageRead(i->first,false);
322 /// Already requested : change the priority
323 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
324 pitl->SetPriority(priority);
326 if (pitl->Index()>=0)
329 mQueue.upsort(pitl->Index());
331 // Not read but not in queue = being read = ok
339 // Never requested before or unloaded
340 ImageToLoadPtr pitl = new ImageToLoad(user,filename,priority);
345 //=====================================================================
347 //=====================================================================
348 void MultiThreadImageReader::OnMultiThreadImageReaderEvent
349 (const std::string& filename,
350 MultiThreadImageReaderUser::EventType e,
353 if ((e==MultiThreadImageReaderUser::ImageLoaded) &&
354 (filename == mRequestedFilename))
356 mRequestedImage = image;
358 else if (e==MultiThreadImageReaderUser::ThreadedReaderStarted)
360 mNumberOfThreadedReadersRunning++;
361 // std::cout << "#TR=" << mNumberOfThreadedReadersRunning << std::endl;
363 else if (e==MultiThreadImageReaderUser::ThreadedReaderStopped)
366 mNumberOfThreadedReadersRunning--;
367 // std::cout << "#TR=" << mNumberOfThreadedReadersRunning << std::endl;
370 //=====================================================================
372 //=====================================================================
373 vtkImageData* MultiThreadImageReader::GetImage(const std::string& filename)
376 printf("EED MultiThreadImageReader::GetImage Start\n");
381 // wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
383 // std::cout << "** MultiThreadImageReader::GetImage('"<<filename
387 // if (mNumberOfThreadedReadersRunning==0)
388 // if (mThreadedImageReaderList.size()==0)
391 printf("EED MultiThreadImageReader::GetImage 1\n");
392 ImageToLoad itl(this,filename);
393 printf("EED MultiThreadImageReader::GetImage 2\n");
394 ImageMapType::iterator i = mImages.find(&itl);
395 if (i!=mImages.end())
397 printf("EED MultiThreadImageReader::GetImage 2.1\n");
398 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
399 printf("EED MultiThreadImageReader::GetImage 2.2\n");
401 if (pitl->GetImage() != NULL)
404 UpdateUnloadPriority( pitl, GetMaximalPriorityWithoutLocking()+1 );
405 return pitl->GetImage();
406 } // if pitl->GetImage()
409 printf("EED MultiThreadImageReader::GetImage 3.1\n");
410 ImageToLoadPtr pitl = new ImageToLoad(this,filename,0);
411 printf("EED MultiThreadImageReader::GetImage 3.2\n");
412 mImages[pitl] = NULL;
413 pitl->SetImage( mReader->ReadImage(filename) );
414 printf("EED MultiThreadImageReader::GetImage 3.3\n");
415 UpdateUnloadPriority( pitl, GetMaximalPriorityWithoutLocking()+1 );
416 printf("EED MultiThreadImageReader::GetImage 3.4\n");
417 return pitl->GetImage();
421 mRequestedFilename = filename;
423 ImageToLoad itl(this,filename);
424 ImageMapType::iterator i = mImages.find(&itl);
425 if (i!=mImages.end())
427 // Already inserted in queue
428 if (i->first->GetImage() != 0)
430 // Already read : ok : return it
431 return i->first->GetImage();
433 /// Already requested : change the priority
434 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
435 pitl->SetPriority( GetMaximalPriorityWithoutLocking() + 1 );
436 pitl->SetUser( this );
438 if (pitl->Index()>=0)
441 mQueue.upsort(pitl->Index());
443 // Not read but not in queue = being read = ok
446 pitl->SetUser( this );
452 // Never requested before or unloaded
453 ImageToLoadPtr pitl =
454 new ImageToLoad(this,filename,
455 GetMaximalPriorityWithoutLocking() + 1);
463 // std::cout << "Waiting..."<<std::endl;
466 // Waiting that it is read
470 // std::cout << n++ << std::endl;
474 // wxMutexLocker lock(mMutex);
475 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex());
476 if (mRequestedImage!=0)
478 return mRequestedImage;
486 printf("EED MultiThreadImageReader::GetImage END\n");
489 //=====================================================================
491 //=====================================================================
492 void MultiThreadImageReader::SignalImageRead(ImageToLoadPtr p,
496 // std::cout << "MultiThreadImageReader::SignalImageRead" <<std::endl;
497 // std::cout << "this="<<this <<std::endl;
498 // std::cout << "user="<<p->GetUser() <<std::endl;
500 if ( p->GetUser() == this )
502 GetMultiThreadImageReaderUserMutex().Unlock();
505 p->GetUser()->MultiThreadImageReaderSendEvent
507 MultiThreadImageReaderUser::ImageLoaded,
511 AN ATTEMPT TO UNLOAD OLDEST IMAGE IF EXCEEDED A CERTAIN MEMORY QUOTA
515 GimmickMessage(5,"Image '"<<p->GetFilename()<<"' read"<<std::endl);
517 // wxMutexLocker lock(GetMultiThreadImageReaderUserMutex());
519 mUnloadQueue.insert(p);
522 //EED 2017-01-01 Migration VTK7
523 #if VTK_MAJOR_VERSION <= 5
524 p->GetImage()->UpdateInformation();
525 p->GetImage()->PropagateUpdateExtent();
526 long ImMem = p->GetImage()->GetEstimatedMemorySize();
530 p->GetImage()->GetExtent(ext);
531 dim[0] = ext[1]-ext[0]+1;
532 dim[1] = ext[3]-ext[2]+1;
533 dim[2] = ext[5]-ext[4]+1;
534 long ImMem = dim[0]*dim[1]*dim[2]*p->GetImage()->GetScalarSize();;
538 GimmickMessage(5,"==> Image in memory = "<<mUnloadQueue.size()<<std::endl);
539 GimmickMessage(5,"==> Total mem = "<<mTotalMem<<" Ko"<<std::endl);
543 while (mTotalMem > mTotalMemMax)
546 " ! Exceeded max of "
547 << mTotalMemMax << " Ko : unloading oldest image ... "
549 if ( mUnloadQueue.size() <= 1 )
552 " Only one image : cannot load AND unload it !!"
557 ImageToLoadPtr unload = mUnloadQueue.remove_top();
558 MultiThreadImageReaderUser* user = unload->GetUser();
561 if ((user!=0)&&(user!=this))
563 user->GetMultiThreadImageReaderUserMutex().Lock();
567 std::string filename = unload->GetFilename();
569 GimmickMessage(5,"'" << filename << "'" << std::endl);
571 //EED 2017-01-01 Migration VTK7
572 #if VTK_MAJOR_VERSION <= 5
573 mTotalMem -= unload->GetImage()->GetEstimatedMemorySize();
577 unload->GetImage()->GetExtent(ext);
578 dim[0] = ext[1]-ext[0]+1;
579 dim[1] = ext[3]-ext[2]+1;
580 dim[2] = ext[5]-ext[4]+1;
581 mTotalMem -= dim[0]*dim[1]*dim[2]*unload->GetImage()->GetScalarSize();
584 GimmickMessage(5," ==> Total mem = "<<mTotalMem<<" Ko "<<std::endl);
588 // std::cout << "unlock..."<<std::endl;
589 // user->GetMultiThreadImageReaderUserMutex().Unlock();
590 // std::cout << "event"<<std::endl;
591 user->MultiThreadImageReaderSendEvent
593 MultiThreadImageReaderUser::ImageUnloaded,
595 // std::cout << "event ok"<<std::endl;
598 if (unload->Index()>=0)
600 // GimmickMessage(5,"still in queue"<<std::endl);
602 unload->Index() = -1;
605 ImageMapType::iterator it = mImages.find(unload);
606 if (it!=mImages.end())
610 // std::cout << "delete..."<<std::endl;
612 // std::cout << "delete ok."<<std::endl;
616 //=====================================================================
618 //=====================================================================
619 int MultiThreadImageReader::GetMaximalPriority()
621 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
622 return GetMaximalPriorityWithoutLocking();
624 //=====================================================================
627 //=====================================================================
628 int MultiThreadImageReader::GetMaximalPriorityWithoutLocking()
633 max = mQueue.top()->GetPriority();
635 if (mUnloadQueue.size()>0)
637 int max2 = mUnloadQueue.top()->GetPriority();
638 if (max2>max) max=max2;
642 //=====================================================================
645 //=====================================================================
646 //=====================================================================
647 //=====================================================================
648 //=====================================================================
650 //=====================================================================
651 void* ThreadedImageReader::Entry()
653 // std::cout << "### Thread "<<GetCurrentId()<<"::Entry()"
656 mMultiThreadImageReader->MultiThreadImageReaderSendEvent
658 MultiThreadImageReaderUser::ThreadedReaderStarted,
661 // While was not deleted
662 while (!TestDestroy())
664 //std::cout << "### Thread "<<GetCurrentId()<<" still alive" << std::endl;
667 mMultiThreadImageReader->MultiThreadImageReaderEventLock();
670 if (mMultiThreadImageReader->mQueue.size()>0)
672 MultiThreadImageReader::ImageToLoadPtr i =
673 mMultiThreadImageReader->mQueue.remove_top();
675 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();
679 // std::cout << "### Thread "<<GetCurrentId()<<" : reading '"
680 // << i->GetFilename() << "'" << std::endl;
683 vtkImageData* im = Read(i->GetFilename());
685 // Store it in the map
686 mMultiThreadImageReader->MultiThreadImageReaderEventLock();
688 MultiThreadImageReader::ImageToLoad itl(0,i->GetFilename());
689 MultiThreadImageReader::ImageMapType::iterator it =
690 mMultiThreadImageReader->mImages.find(&itl);
691 MultiThreadImageReader::ImageToLoadPtr
692 pitl = const_cast<MultiThreadImageReader::ImageToLoadPtr>
695 mMultiThreadImageReader->SignalImageRead(pitl,true);//i->GetFilename());
696 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock(); //mMutex.Unlock();
698 // std::cout << "### Thread "<<GetCurrentId()<<" : reading '"
699 // << i->GetFilename() << "' : DONE" << std::endl;
702 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();
704 // Wait a little to avoid blocking
708 // std::cout << "### Thread "<<GetCurrentId()<<" stopping"
713 //=====================================================================
715 //=====================================================================
716 void ThreadedImageReader::OnExit()
718 mMultiThreadImageReader->MultiThreadImageReaderSendEvent
720 MultiThreadImageReaderUser::ThreadedReaderStopped,
723 //=====================================================================
725 //=====================================================================
726 vtkImageData* ThreadedImageReader::Read(const std::string& filename)
728 return mReader.ReadImage(filename);
730 //=====================================================================
732 } // namespace creaImageIO