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 <creaImageIOGimmick.h>
41 //=====================================================================
42 void MultiThreadImageReaderUser::MultiThreadImageReaderSendEvent
43 ( const std::string& filename,
47 wxMutexLocker lock(mMultiThreadImageReaderUserMutex);
48 this->OnMultiThreadImageReaderEvent(filename,type,image);
50 //=====================================================================
52 //=====================================================================
53 class ThreadedImageReader: public wxThread
56 ThreadedImageReader(MultiThreadImageReader* tir) :
57 mMultiThreadImageReader(tir)
61 vtkImageData* Read(const std::string& filename);
64 void operator()(ThreadedImageReader* p)
69 friend struct deleter;
73 MultiThreadImageReader* mMultiThreadImageReader;
76 //=====================================================================
79 //=====================================================================
80 MultiThreadImageReader::MultiThreadImageReader(int number_of_threads)
81 : //mDoNotSignal(false),
86 // std::cout << "#### MultiThreadImageReader::MultiThreadImageReader("
87 // << " #threads= " << number_of_threads <<" )"<<std::endl;
92 printf("EED MultiThreadImageReader::MultiThreadImageReader %d \n", number_of_threads);
94 for (int i=0; i<number_of_threads; i++)
96 //ThreadedImageReader* t = new ThreadedImageReader(this);
97 boost::shared_ptr<ThreadedImageReader> t(new ThreadedImageReader(this), ThreadedImageReader::deleter());
98 mThreadedImageReaderList.push_back(t);
99 std::cout << " ===> Thread "<<i
100 <<" successfully added"<< std::endl;
102 mNumberOfThreadedReadersRunning = 0;
104 mQueue.set(mComparator);
105 mQueue.set(mIndexer);
107 // no thread : alloc self reader
108 // if (number_of_threads==0)
110 mReader = new ImageReader();
113 //=====================================================================
116 //=====================================================================
117 bool MultiThreadImageReader::Start()
119 printf("EED MultiThreadImageReader::Start Start\n");
120 // std::cout << "#### MultiThreadImageReader::Start()"
122 if (mNumberOfThreadedReadersRunning > 0) return true;
124 ThreadedImageReaderListType::iterator i;
125 for (i =mThreadedImageReaderList.begin();
126 i!=mThreadedImageReaderList.end();
130 if ( (*i)->Run() != wxTHREAD_NO_ERROR )
132 std::cout << "ERROR starting a thread"<< std::endl;
135 std::cout << " ===> Thread "<<(*i)->GetCurrentId()
136 <<" successfully created"<< std::endl;
139 wxMutexLocker locker(GetMultiThreadImageReaderUserMutex());
140 // std::cout << "EO Start : #Threads running = "
141 // << mNumberOfThreadedReadersRunning<<std::endl;
142 printf("EED MultiThreadImageReader::Start Start\n");
145 //=====================================================================
147 //=====================================================================
148 void MultiThreadImageReader::Stop()
150 printf("EED MultiThreadImageReader::Stop Start\n");
151 // std::cout << "#### MultiThreadImageReader::Stop()"
153 // std::cout << "Sending stop order to the threads..."<<std::endl;
157 ThreadedImageReaderListType::iterator i;
158 for (i =mThreadedImageReaderList.begin();
159 i!=mThreadedImageReaderList.end();
162 std::cout << " ===> Thread "<<(*i)->GetCurrentId()
163 <<" successfully stopped"<< std::endl;
171 mThreadedImageReaderList.clear();
172 // Wait a little to be sure that all threads have stopped
173 // A better way to do this ?
174 // wxMilliSleep(1000);
175 // New method : the threads generate a stop event when they have finished
176 // We wait until all threads have stopped
177 // std::cout << "Waiting for stop signals..."<<std::endl;
184 wxMutexLocker locker(GetMultiThreadImageReaderUserMutex());
185 // std::cout << "#Threads running = "
186 // << mNumberOfThreadedReadersRunning<<std::endl;
187 // Break if all readers have stopped
188 if (mNumberOfThreadedReadersRunning <= 0)
195 // std::cout << "All threads stopped : OK "<<std::endl;
197 ImageMapType::iterator j;
198 for (j =mImages.begin(); j!=mImages.end(); ++j)
204 printf("EED MultiThreadImageReader::Stop End\n");
206 //=====================================================================
208 //=====================================================================
209 MultiThreadImageReader::~MultiThreadImageReader()
211 printf("EED MultiThreadImageReader::~MultiThreadImageReader Start\n");
212 // std::cout << "#### MultiThreadImageReader::~MultiThreadImageReader()"
215 if (mReader) delete mReader;
216 mThreadedImageReaderList.clear();
217 printf("EED MultiThreadImageReader::~MultiThreadImageReader End\n");
219 //=====================================================================
221 //=====================================================================
222 void MultiThreadImageReader::UpdateUnloadPriority(ImageToLoadPtr p,
225 // not in unload queue : ciao
226 if (p->UnloadIndex()<0) return;
227 int old_prio = p->GetPriority();
228 if (priority > old_prio)
230 p->SetPriority(priority);
231 mUnloadQueue.downsort(p->UnloadIndex());
233 else if ( old_prio > priority )
235 p->SetPriority(priority);
236 mUnloadQueue.upsort(p->UnloadIndex());
239 //=====================================================================
240 // function to read attributes for a file
241 void MultiThreadImageReader::getAttributes(const std::string filename,
242 std::map <std::string , std::string> &infos,std::vector<std::string> i_attr)
244 mReader->getAttributes(filename, infos, i_attr);
247 //=====================================================================
248 void MultiThreadImageReader::Request( MultiThreadImageReaderUser* user,
249 const std::string& filename,
252 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
254 if (mNumberOfThreadedReadersRunning==0)
255 // if (mThreadedImageReaderList.size()==0)
257 // no detached reader : use self reader
258 ImageToLoad itl(user,filename);
259 ImageMapType::iterator i = mImages.find(&itl);
260 if (i!=mImages.end())
262 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
264 if (pitl->GetImage() != 0)
268 UpdateUnloadPriority(pitl,priority);
269 SignalImageRead(pitl,false);
270 return; // pitl->GetImage();
273 ImageToLoadPtr pitl = new ImageToLoad(user,filename,0);
275 pitl->SetImage(mReader->ReadImage(filename));
276 UpdateUnloadPriority(pitl,priority);
277 SignalImageRead(pitl,true);
278 // return pitl->GetImage();
282 ImageToLoad itl(user,filename);
283 ImageMapType::iterator i = mImages.find(&itl);
284 if (i!=mImages.end())
287 if (i->first->GetImage() != 0)
289 // Already read : ok :signal the user
290 UpdateUnloadPriority(i->first,priority);
291 SignalImageRead(i->first,false);
294 /// Already requested : change the priority
295 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
296 pitl->SetPriority(priority);
298 if (pitl->Index()>=0)
301 mQueue.upsort(pitl->Index());
303 // Not read but not in queue = being read = ok
311 // Never requested before or unloaded
312 ImageToLoadPtr pitl = new ImageToLoad(user,filename,priority);
317 //=====================================================================
319 //=====================================================================
320 void MultiThreadImageReader::OnMultiThreadImageReaderEvent
321 (const std::string& filename,
322 MultiThreadImageReaderUser::EventType e,
325 if ((e==MultiThreadImageReaderUser::ImageLoaded) &&
326 (filename == mRequestedFilename))
328 mRequestedImage = image;
330 else if (e==MultiThreadImageReaderUser::ThreadedReaderStarted)
332 mNumberOfThreadedReadersRunning++;
333 // std::cout << "#TR=" << mNumberOfThreadedReadersRunning << std::endl;
335 else if (e==MultiThreadImageReaderUser::ThreadedReaderStopped)
338 mNumberOfThreadedReadersRunning--;
339 // std::cout << "#TR=" << mNumberOfThreadedReadersRunning << std::endl;
342 //=====================================================================
344 //=====================================================================
345 vtkImageData* MultiThreadImageReader::GetImage(const std::string& filename)
348 // std::cout << "** MultiThreadImageReader::GetImage('"<<filename<<"')"
353 // wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
355 // std::cout << "** MultiThreadImageReader::GetImage('"<<filename
359 // if (mNumberOfThreadedReadersRunning==0)
360 // if (mThreadedImageReaderList.size()==0)
363 ImageToLoad itl(this,filename);
364 ImageMapType::iterator i = mImages.find(&itl);
365 if (i!=mImages.end())
367 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
369 if (pitl->GetImage() != 0)
372 UpdateUnloadPriority(pitl,
373 GetMaximalPriorityWithoutLocking()+1);
374 return pitl->GetImage();
377 ImageToLoadPtr pitl = new ImageToLoad(this,filename,0);
379 pitl->SetImage(mReader->ReadImage(filename));
380 UpdateUnloadPriority(pitl,
381 GetMaximalPriorityWithoutLocking()+1);
382 return pitl->GetImage();
386 mRequestedFilename = filename;
388 ImageToLoad itl(this,filename);
389 ImageMapType::iterator i = mImages.find(&itl);
390 if (i!=mImages.end())
392 // Already inserted in queue
393 if (i->first->GetImage() != 0)
395 // Already read : ok : return it
396 return i->first->GetImage();
398 /// Already requested : change the priority
399 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
400 pitl->SetPriority( GetMaximalPriorityWithoutLocking() + 1 );
401 pitl->SetUser( this );
403 if (pitl->Index()>=0)
406 mQueue.upsort(pitl->Index());
408 // Not read but not in queue = being read = ok
411 pitl->SetUser( this );
417 // Never requested before or unloaded
418 ImageToLoadPtr pitl =
419 new ImageToLoad(this,filename,
420 GetMaximalPriorityWithoutLocking() + 1);
428 // std::cout << "Waiting..."<<std::endl;
431 // Waiting that it is read
435 // std::cout << n++ << std::endl;
439 // wxMutexLocker lock(mMutex);
440 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex());
441 if (mRequestedImage!=0)
443 return mRequestedImage;
452 //=====================================================================
454 //=====================================================================
455 void MultiThreadImageReader::SignalImageRead(ImageToLoadPtr p,
459 // std::cout << "MultiThreadImageReader::SignalImageRead" <<std::endl;
460 // std::cout << "this="<<this <<std::endl;
461 // std::cout << "user="<<p->GetUser() <<std::endl;
463 if ( p->GetUser() == this )
465 GetMultiThreadImageReaderUserMutex().Unlock();
468 p->GetUser()->MultiThreadImageReaderSendEvent
470 MultiThreadImageReaderUser::ImageLoaded,
474 AN ATTEMPT TO UNLOAD OLDEST IMAGE IF EXCEEDED A CERTAIN MEMORY QUOTA
478 GimmickMessage(5,"Image '"<<p->GetFilename()<<"' read"<<std::endl);
480 // wxMutexLocker lock(GetMultiThreadImageReaderUserMutex());
482 mUnloadQueue.insert(p);
485 //EED 2017-01-01 Migration VTK7
486 #if VTK_MAJOR_VERSION <= 5
487 p->GetImage()->UpdateInformation();
488 p->GetImage()->PropagateUpdateExtent();
489 long ImMem = p->GetImage()->GetEstimatedMemorySize();
493 p->GetImage()->GetExtent(ext);
494 dim[0] = ext[1]-ext[0]+1;
495 dim[1] = ext[3]-ext[2]+1;
496 dim[2] = ext[5]-ext[4]+1;
497 long ImMem = dim[0]*dim[1]*dim[2]*p->GetImage()->GetScalarSize();;
501 GimmickMessage(5,"==> Image in memory = "<<mUnloadQueue.size()<<std::endl);
502 GimmickMessage(5,"==> Total mem = "<<mTotalMem<<" Ko"<<std::endl);
506 while (mTotalMem > mTotalMemMax)
509 " ! Exceeded max of "
510 << mTotalMemMax << " Ko : unloading oldest image ... "
512 if ( mUnloadQueue.size() <= 1 )
515 " Only one image : cannot load AND unload it !!"
520 ImageToLoadPtr unload = mUnloadQueue.remove_top();
521 MultiThreadImageReaderUser* user = unload->GetUser();
524 if ((user!=0)&&(user!=this))
526 user->GetMultiThreadImageReaderUserMutex().Lock();
530 std::string filename = unload->GetFilename();
532 GimmickMessage(5,"'" << filename << "'" << std::endl);
534 //EED 2017-01-01 Migration VTK7
535 #if VTK_MAJOR_VERSION <= 5
536 mTotalMem -= unload->GetImage()->GetEstimatedMemorySize();
540 unload->GetImage()->GetExtent(ext);
541 dim[0] = ext[1]-ext[0]+1;
542 dim[1] = ext[3]-ext[2]+1;
543 dim[2] = ext[5]-ext[4]+1;
544 mTotalMem -= dim[0]*dim[1]*dim[2]*unload->GetImage()->GetScalarSize();
547 GimmickMessage(5," ==> Total mem = "<<mTotalMem<<" Ko "<<std::endl);
551 // std::cout << "unlock..."<<std::endl;
552 // user->GetMultiThreadImageReaderUserMutex().Unlock();
553 // std::cout << "event"<<std::endl;
554 user->MultiThreadImageReaderSendEvent
556 MultiThreadImageReaderUser::ImageUnloaded,
558 // std::cout << "event ok"<<std::endl;
561 if (unload->Index()>=0)
563 // GimmickMessage(5,"still in queue"<<std::endl);
565 unload->Index() = -1;
568 ImageMapType::iterator it = mImages.find(unload);
569 if (it!=mImages.end())
573 // std::cout << "delete..."<<std::endl;
575 // std::cout << "delete ok."<<std::endl;
579 //=====================================================================
581 //=====================================================================
582 int MultiThreadImageReader::GetMaximalPriority()
584 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
585 return GetMaximalPriorityWithoutLocking();
587 //=====================================================================
590 //=====================================================================
591 int MultiThreadImageReader::GetMaximalPriorityWithoutLocking()
596 max = mQueue.top()->GetPriority();
598 if (mUnloadQueue.size()>0)
600 int max2 = mUnloadQueue.top()->GetPriority();
601 if (max2>max) max=max2;
605 //=====================================================================
608 //=====================================================================
609 //=====================================================================
610 //=====================================================================
611 //=====================================================================
613 //=====================================================================
614 void* ThreadedImageReader::Entry()
616 // std::cout << "### Thread "<<GetCurrentId()<<"::Entry()"
619 mMultiThreadImageReader->MultiThreadImageReaderSendEvent
621 MultiThreadImageReaderUser::ThreadedReaderStarted,
624 // While was not deleted
625 while (!TestDestroy())
627 //std::cout << "### Thread "<<GetCurrentId()<<" still alive" << std::endl;
630 mMultiThreadImageReader->MultiThreadImageReaderEventLock();
633 if (mMultiThreadImageReader->mQueue.size()>0)
635 MultiThreadImageReader::ImageToLoadPtr i =
636 mMultiThreadImageReader->mQueue.remove_top();
638 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();
642 // std::cout << "### Thread "<<GetCurrentId()<<" : reading '"
643 // << i->GetFilename() << "'" << std::endl;
646 vtkImageData* im = Read(i->GetFilename());
648 // Store it in the map
649 mMultiThreadImageReader->MultiThreadImageReaderEventLock();
651 MultiThreadImageReader::ImageToLoad itl(0,i->GetFilename());
652 MultiThreadImageReader::ImageMapType::iterator it =
653 mMultiThreadImageReader->mImages.find(&itl);
654 MultiThreadImageReader::ImageToLoadPtr
655 pitl = const_cast<MultiThreadImageReader::ImageToLoadPtr>
658 mMultiThreadImageReader->SignalImageRead(pitl,true);//i->GetFilename());
659 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock(); //mMutex.Unlock();
661 // std::cout << "### Thread "<<GetCurrentId()<<" : reading '"
662 // << i->GetFilename() << "' : DONE" << std::endl;
665 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();
667 // Wait a little to avoid blocking
671 // std::cout << "### Thread "<<GetCurrentId()<<" stopping"
676 //=====================================================================
678 //=====================================================================
679 void ThreadedImageReader::OnExit()
681 mMultiThreadImageReader->MultiThreadImageReaderSendEvent
683 MultiThreadImageReaderUser::ThreadedReaderStopped,
686 //=====================================================================
688 //=====================================================================
689 vtkImageData* ThreadedImageReader::Read(const std::string& filename)
691 return mReader.ReadImage(filename);
693 //=====================================================================
695 } // namespace creaImageIO