1 #include <creaImageIOMultiThreadImageReader.h>
2 #include <creaImageIOImageReader.h>
4 #include <creaImageIOSystem.h>
9 //=====================================================================
10 void MultiThreadImageReaderUser::MultiThreadImageReaderSendEvent
11 ( const std::string& filename,
15 wxMutexLocker lock(mMultiThreadImageReaderUserMutex);
17 this->OnMultiThreadImageReaderEvent(filename,type,image);
19 //=====================================================================
21 //=====================================================================
22 class ThreadedImageReader: public wxThread
25 ThreadedImageReader(MultiThreadImageReader* tir) :
26 mMultiThreadImageReader(tir)
32 vtkImageData* Read(const std::string& filename);
36 void operator()(ThreadedImageReader* p)
41 friend struct deleter;
46 MultiThreadImageReader* mMultiThreadImageReader;
50 //=====================================================================
53 //=====================================================================
54 MultiThreadImageReader::MultiThreadImageReader(int number_of_threads)
55 : //mDoNotSignal(false),
60 // std::cout << "#### MultiThreadImageReader::MultiThreadImageReader("
61 // << " #threads= " << number_of_threads <<" )"<<std::endl;
64 for (int i=0; i<number_of_threads; i++)
66 //ThreadedImageReader* t = new ThreadedImageReader(this);
67 boost::shared_ptr<ThreadedImageReader> t(new ThreadedImageReader(this), ThreadedImageReader::deleter());
68 mThreadedImageReaderList.push_back(t);
69 std::cout << " ===> Thread "<<i
70 <<" successfully added"<< std::endl;
72 mNumberOfThreadedReadersRunning = 0;
74 mQueue.set(mComparator);
77 // no thread : alloc self reader
78 // if (number_of_threads==0)
80 mReader = new ImageReader();
83 //=====================================================================
86 //=====================================================================
87 bool MultiThreadImageReader::Start()
90 // std::cout << "#### MultiThreadImageReader::Start()"
92 if (mNumberOfThreadedReadersRunning > 0) return true;
94 ThreadedImageReaderListType::iterator i;
95 for (i =mThreadedImageReaderList.begin();
96 i!=mThreadedImageReaderList.end();
100 if ( (*i)->Run() != wxTHREAD_NO_ERROR )
102 std::cout << "ERROR starting a thread"<< std::endl;
107 std::cout << " ===> Thread "<<(*i)->GetCurrentId()
108 <<" successfully created"<< std::endl;
112 wxMutexLocker locker(GetMultiThreadImageReaderUserMutex());
113 // std::cout << "EO Start : #Threads running = "
114 // << mNumberOfThreadedReadersRunning<<std::endl;
118 //=====================================================================
120 //=====================================================================
121 void MultiThreadImageReader::Stop()
123 // std::cout << "#### MultiThreadImageReader::Stop()"
125 // std::cout << "Sending stop order to the threads..."<<std::endl;
127 ThreadedImageReaderListType::iterator i;
128 for (i =mThreadedImageReaderList.begin();
129 i!=mThreadedImageReaderList.end();
131 { std::cout << " ===> Thread "<<(*i)->GetCurrentId()
132 <<" successfully stopped"<< std::endl;
139 // mThreadedImageReaderList.clear();
140 // Wait a little to be sure that all threads have stopped
141 // A better way to do this ?
142 // wxMilliSleep(1000);
143 // New method : the threads generate a stop event when they have finished
144 // We wait until all threads have stopped
145 // std::cout << "Waiting for stop signals..."<<std::endl;
152 wxMutexLocker locker(GetMultiThreadImageReaderUserMutex());
153 // std::cout << "#Threads running = "
154 // << mNumberOfThreadedReadersRunning<<std::endl;
155 // Break if all readers have stopped
156 if (mNumberOfThreadedReadersRunning <= 0)
163 // std::cout << "All threads stopped : OK "<<std::endl;
165 ImageMapType::iterator j;
166 for (j =mImages.begin();
175 //=====================================================================
177 //=====================================================================
178 MultiThreadImageReader::~MultiThreadImageReader()
180 // std::cout << "#### MultiThreadImageReader::~MultiThreadImageReader()"
183 if (mReader) delete mReader;
184 mThreadedImageReaderList.clear();
186 //=====================================================================
188 //=====================================================================
189 void MultiThreadImageReader::UpdateUnloadPriority(ImageToLoadPtr p,
192 // not in unload queue : ciao
193 if (p->UnloadIndex()<0) return;
194 int old_prio = p->GetPriority();
195 if (priority > old_prio)
197 p->SetPriority(priority);
198 mUnloadQueue.downsort(p->UnloadIndex());
200 else if ( old_prio > priority )
202 p->SetPriority(priority);
203 mUnloadQueue.upsort(p->UnloadIndex());
206 //=====================================================================
208 //=====================================================================
209 void MultiThreadImageReader::Request( MultiThreadImageReaderUser* user,
210 const std::string& filename,
213 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
215 if (mNumberOfThreadedReadersRunning==0)
216 // if (mThreadedImageReaderList.size()==0)
218 // no detached reader : use self reader
219 ImageToLoad itl(user,filename);
220 ImageMapType::iterator i = mImages.find(&itl);
221 if (i!=mImages.end())
223 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
225 if (pitl->GetImage() != 0)
229 UpdateUnloadPriority(pitl,priority);
230 SignalImageRead(pitl,false);
231 return; // pitl->GetImage();
234 ImageToLoadPtr pitl = new ImageToLoad(user,filename,0);
236 pitl->SetImage(mReader->ReadImage(filename));
237 UpdateUnloadPriority(pitl,priority);
238 SignalImageRead(pitl,true);
239 // return pitl->GetImage();
243 ImageToLoad itl(user,filename);
244 ImageMapType::iterator i = mImages.find(&itl);
245 if (i!=mImages.end())
248 if (i->first->GetImage() != 0)
250 // Already read : ok :signal the user
251 UpdateUnloadPriority(i->first,priority);
252 SignalImageRead(i->first,false);
255 /// Already requested : change the priority
256 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
257 pitl->SetPriority(priority);
259 if (pitl->Index()>=0)
262 mQueue.upsort(pitl->Index());
264 // Not read but not in queue = being read = ok
272 // Never requested before or unloaded
273 ImageToLoadPtr pitl = new ImageToLoad(user,filename,priority);
278 //=====================================================================
280 //=====================================================================
281 void MultiThreadImageReader::OnMultiThreadImageReaderEvent
282 (const std::string& filename,
283 MultiThreadImageReaderUser::EventType e,
286 if ((e==MultiThreadImageReaderUser::ImageLoaded) &&
287 (filename == mRequestedFilename))
289 mRequestedImage = image;
291 else if (e==MultiThreadImageReaderUser::ThreadedReaderStarted)
293 mNumberOfThreadedReadersRunning++;
294 // std::cout << "#TR=" << mNumberOfThreadedReadersRunning << std::endl;
296 else if (e==MultiThreadImageReaderUser::ThreadedReaderStopped)
299 mNumberOfThreadedReadersRunning--;
300 // std::cout << "#TR=" << mNumberOfThreadedReadersRunning << std::endl;
303 //=====================================================================
305 //=====================================================================
306 vtkImageData* MultiThreadImageReader::GetImage(const std::string& filename)
309 // std::cout << "** MultiThreadImageReader::GetImage('"<<filename<<"')"
314 // wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
316 // std::cout << "** MultiThreadImageReader::GetImage('"<<filename
320 // if (mNumberOfThreadedReadersRunning==0)
321 // if (mThreadedImageReaderList.size()==0)
324 ImageToLoad itl(this,filename);
325 ImageMapType::iterator i = mImages.find(&itl);
326 if (i!=mImages.end())
328 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
330 if (pitl->GetImage() != 0)
333 UpdateUnloadPriority(pitl,
334 GetMaximalPriorityWithoutLocking()+1);
335 return pitl->GetImage();
338 ImageToLoadPtr pitl = new ImageToLoad(this,filename,0);
340 pitl->SetImage(mReader->ReadImage(filename));
341 UpdateUnloadPriority(pitl,
342 GetMaximalPriorityWithoutLocking()+1);
343 return pitl->GetImage();
347 mRequestedFilename = filename;
349 ImageToLoad itl(this,filename);
350 ImageMapType::iterator i = mImages.find(&itl);
351 if (i!=mImages.end())
353 // Already inserted in queue
354 if (i->first->GetImage() != 0)
356 // Already read : ok : return it
357 return i->first->GetImage();
359 /// Already requested : change the priority
360 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
361 pitl->SetPriority( GetMaximalPriorityWithoutLocking() + 1 );
362 pitl->SetUser( this );
364 if (pitl->Index()>=0)
367 mQueue.upsort(pitl->Index());
369 // Not read but not in queue = being read = ok
372 pitl->SetUser( this );
378 // Never requested before or unloaded
379 ImageToLoadPtr pitl =
380 new ImageToLoad(this,filename,
381 GetMaximalPriorityWithoutLocking() + 1);
389 // std::cout << "Waiting..."<<std::endl;
392 // Waiting that it is read
396 // std::cout << n++ << std::endl;
400 // wxMutexLocker lock(mMutex);
401 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex());
402 if (mRequestedImage!=0)
404 return mRequestedImage;
413 //=====================================================================
415 //=====================================================================
416 void MultiThreadImageReader::SignalImageRead(ImageToLoadPtr p,
420 // std::cout << "MultiThreadImageReader::SignalImageRead" <<std::endl;
421 // std::cout << "this="<<this <<std::endl;
422 // std::cout << "user="<<p->GetUser() <<std::endl;
424 if ( p->GetUser() == this )
425 GetMultiThreadImageReaderUserMutex().Unlock();
427 p->GetUser()->MultiThreadImageReaderSendEvent
429 MultiThreadImageReaderUser::ImageLoaded,
433 AN ATTEMPT TO UNLOAD OLDEST IMAGE IF EXCEEDED A CERTAIN MEMORY QUOTA
437 GimmickMessage(5,"Image '"<<p->GetFilename()<<"' read"<<std::endl);
439 // wxMutexLocker lock(GetMultiThreadImageReaderUserMutex());
441 mUnloadQueue.insert(p);
442 p->GetImage()->UpdateInformation();
443 p->GetImage()->PropagateUpdateExtent();
444 long ImMem = p->GetImage()->GetEstimatedMemorySize();
447 GimmickMessage(5,"==> Image in memory = "<<mUnloadQueue.size()<<std::endl);
448 GimmickMessage(5,"==> Total mem = "<<mTotalMem<<" Ko"<<std::endl);
452 while (mTotalMem > mTotalMemMax)
455 " ! Exceeded max of "
456 << mTotalMemMax << " Ko : unloading oldest image ... "
458 if ( mUnloadQueue.size() <= 1 )
461 " Only one image : cannot load AND unload it !!"
466 ImageToLoadPtr unload = mUnloadQueue.remove_top();
467 MultiThreadImageReaderUser* user = unload->GetUser();
470 if ((user!=0)&&(user!=this))
472 user->GetMultiThreadImageReaderUserMutex().Lock();
476 std::string filename = unload->GetFilename();
478 GimmickMessage(5,"'" << filename << "'" << std::endl);
479 mTotalMem -= unload->GetImage()->GetEstimatedMemorySize();
481 GimmickMessage(5," ==> Total mem = "<<mTotalMem<<" Ko "<<std::endl);
485 // std::cout << "unlock..."<<std::endl;
486 // user->GetMultiThreadImageReaderUserMutex().Unlock();
487 // std::cout << "event"<<std::endl;
488 user->MultiThreadImageReaderSendEvent
490 MultiThreadImageReaderUser::ImageUnloaded,
492 // std::cout << "event ok"<<std::endl;
495 if (unload->Index()>=0)
497 // GimmickMessage(5,"still in queue"<<std::endl);
499 unload->Index() = -1;
502 ImageMapType::iterator it = mImages.find(unload);
503 if (it!=mImages.end())
507 // std::cout << "delete..."<<std::endl;
509 // std::cout << "delete ok."<<std::endl;
513 //=====================================================================
515 //=====================================================================
516 int MultiThreadImageReader::GetMaximalPriority()
518 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
519 return GetMaximalPriorityWithoutLocking();
521 //=====================================================================
524 //=====================================================================
525 int MultiThreadImageReader::GetMaximalPriorityWithoutLocking()
530 max = mQueue.top()->GetPriority();
532 if (mUnloadQueue.size()>0)
534 int max2 = mUnloadQueue.top()->GetPriority();
535 if (max2>max) max=max2;
539 //=====================================================================
542 //=====================================================================
543 //=====================================================================
544 //=====================================================================
545 //=====================================================================
547 //=====================================================================
548 void* ThreadedImageReader::Entry()
550 // std::cout << "### Thread "<<GetCurrentId()<<"::Entry()"
553 mMultiThreadImageReader->MultiThreadImageReaderSendEvent
555 MultiThreadImageReaderUser::ThreadedReaderStarted,
558 // While was not deleted
559 while (!TestDestroy())
561 //std::cout << "### Thread "<<GetCurrentId()<<" still alive" << std::endl;
564 mMultiThreadImageReader->MultiThreadImageReaderEventLock();
567 if (mMultiThreadImageReader->mQueue.size()>0)
569 MultiThreadImageReader::ImageToLoadPtr i =
570 mMultiThreadImageReader->mQueue.remove_top();
572 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();
576 // std::cout << "### Thread "<<GetCurrentId()<<" : reading '"
577 // << i->GetFilename() << "'" << std::endl;
580 vtkImageData* im = Read(i->GetFilename());
582 // Store it in the map
583 mMultiThreadImageReader->MultiThreadImageReaderEventLock();
585 MultiThreadImageReader::ImageToLoad itl(0,i->GetFilename());
586 MultiThreadImageReader::ImageMapType::iterator it =
587 mMultiThreadImageReader->mImages.find(&itl);
588 MultiThreadImageReader::ImageToLoadPtr
589 pitl = const_cast<MultiThreadImageReader::ImageToLoadPtr>
592 mMultiThreadImageReader->SignalImageRead(pitl,true);//i->GetFilename());
593 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock(); //mMutex.Unlock();
595 // std::cout << "### Thread "<<GetCurrentId()<<" : reading '"
596 // << i->GetFilename() << "' : DONE" << std::endl;
601 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();
603 // Wait a little to avoid blocking
607 // std::cout << "### Thread "<<GetCurrentId()<<" stopping"
612 //=====================================================================
614 //=====================================================================
615 void ThreadedImageReader::OnExit()
617 mMultiThreadImageReader->MultiThreadImageReaderSendEvent
619 MultiThreadImageReaderUser::ThreadedReaderStopped,
622 //=====================================================================
624 //=====================================================================
625 vtkImageData* ThreadedImageReader::Read(const std::string& filename)
627 return mReader.ReadImage(filename);
629 //=====================================================================
631 } // namespace creaImageIO