1 #include <creaImageIOMultiThreadImageReader.h>
2 #include <creaImageIOImageReader.h>
4 #include <creaImageIOSystem.h>
6 #include <creaImageIOGimmick.h>
13 //=====================================================================
14 void MultiThreadImageReaderUser::MultiThreadImageReaderSendEvent
15 ( const std::string& filename,
19 wxMutexLocker lock(mMultiThreadImageReaderUserMutex);
21 this->OnMultiThreadImageReaderEvent(filename,type,image);
23 //=====================================================================
25 //=====================================================================
26 class ThreadedImageReader: public wxThread
29 ThreadedImageReader(MultiThreadImageReader* tir) :
30 mMultiThreadImageReader(tir)
36 vtkImageData* Read(const std::string& filename);
40 void operator()(ThreadedImageReader* p)
45 friend struct deleter;
50 MultiThreadImageReader* mMultiThreadImageReader;
54 //=====================================================================
57 //=====================================================================
58 MultiThreadImageReader::MultiThreadImageReader(int number_of_threads)
59 : //mDoNotSignal(false),
64 // std::cout << "#### MultiThreadImageReader::MultiThreadImageReader("
65 // << " #threads= " << number_of_threads <<" )"<<std::endl;
69 for (int i=0; i<number_of_threads; i++)
71 //ThreadedImageReader* t = new ThreadedImageReader(this);
72 boost::shared_ptr<ThreadedImageReader> t(new ThreadedImageReader(this), ThreadedImageReader::deleter());
73 mThreadedImageReaderList.push_back(t);
74 std::cout << " ===> Thread "<<i
75 <<" successfully added"<< std::endl;
77 mNumberOfThreadedReadersRunning = 0;
79 mQueue.set(mComparator);
82 // no thread : alloc self reader
83 // if (number_of_threads==0)
85 mReader = new ImageReader();
88 //=====================================================================
91 //=====================================================================
92 bool MultiThreadImageReader::Start()
95 // std::cout << "#### MultiThreadImageReader::Start()"
97 if (mNumberOfThreadedReadersRunning > 0) return true;
99 ThreadedImageReaderListType::iterator i;
100 for (i =mThreadedImageReaderList.begin();
101 i!=mThreadedImageReaderList.end();
105 if ( (*i)->Run() != wxTHREAD_NO_ERROR )
107 std::cout << "ERROR starting a thread"<< std::endl;
112 std::cout << " ===> Thread "<<(*i)->GetCurrentId()
113 <<" successfully created"<< std::endl;
117 wxMutexLocker locker(GetMultiThreadImageReaderUserMutex());
118 // std::cout << "EO Start : #Threads running = "
119 // << mNumberOfThreadedReadersRunning<<std::endl;
123 //=====================================================================
125 //=====================================================================
126 void MultiThreadImageReader::Stop()
128 // std::cout << "#### MultiThreadImageReader::Stop()"
130 // std::cout << "Sending stop order to the threads..."<<std::endl;
133 ThreadedImageReaderListType::iterator i;
134 for (i =mThreadedImageReaderList.begin();
135 i!=mThreadedImageReaderList.end();
137 { std::cout << " ===> Thread "<<(*i)->GetCurrentId()
138 <<" successfully stopped"<< std::endl;
145 mThreadedImageReaderList.clear();
146 // Wait a little to be sure that all threads have stopped
147 // A better way to do this ?
148 // wxMilliSleep(1000);
149 // New method : the threads generate a stop event when they have finished
150 // We wait until all threads have stopped
151 // std::cout << "Waiting for stop signals..."<<std::endl;
158 wxMutexLocker locker(GetMultiThreadImageReaderUserMutex());
159 // std::cout << "#Threads running = "
160 // << mNumberOfThreadedReadersRunning<<std::endl;
161 // Break if all readers have stopped
162 if (mNumberOfThreadedReadersRunning <= 0)
169 // std::cout << "All threads stopped : OK "<<std::endl;
171 ImageMapType::iterator j;
172 for (j =mImages.begin();
182 //=====================================================================
184 //=====================================================================
185 MultiThreadImageReader::~MultiThreadImageReader()
187 // std::cout << "#### MultiThreadImageReader::~MultiThreadImageReader()"
190 if (mReader) delete mReader;
191 mThreadedImageReaderList.clear();
193 //=====================================================================
195 //=====================================================================
196 void MultiThreadImageReader::UpdateUnloadPriority(ImageToLoadPtr p,
199 // not in unload queue : ciao
200 if (p->UnloadIndex()<0) return;
201 int old_prio = p->GetPriority();
202 if (priority > old_prio)
204 p->SetPriority(priority);
205 mUnloadQueue.downsort(p->UnloadIndex());
207 else if ( old_prio > priority )
209 p->SetPriority(priority);
210 mUnloadQueue.upsort(p->UnloadIndex());
213 //=====================================================================
214 // function to read attributes for a file
215 void MultiThreadImageReader::getAttributes(const std::string filename,
216 std::map <std::string , std::string> &infos,std::vector<std::string> i_attr)
218 mReader->getAttributes(filename, infos, i_attr);
221 //=====================================================================
222 void MultiThreadImageReader::Request( MultiThreadImageReaderUser* user,
223 const std::string& filename,
226 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
228 if (mNumberOfThreadedReadersRunning==0)
229 // if (mThreadedImageReaderList.size()==0)
231 // no detached reader : use self reader
232 ImageToLoad itl(user,filename);
233 ImageMapType::iterator i = mImages.find(&itl);
234 if (i!=mImages.end())
236 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
238 if (pitl->GetImage() != 0)
242 UpdateUnloadPriority(pitl,priority);
243 SignalImageRead(pitl,false);
244 return; // pitl->GetImage();
247 ImageToLoadPtr pitl = new ImageToLoad(user,filename,0);
249 pitl->SetImage(mReader->ReadImage(filename));
250 UpdateUnloadPriority(pitl,priority);
251 SignalImageRead(pitl,true);
252 // return pitl->GetImage();
256 ImageToLoad itl(user,filename);
257 ImageMapType::iterator i = mImages.find(&itl);
258 if (i!=mImages.end())
261 if (i->first->GetImage() != 0)
263 // Already read : ok :signal the user
264 UpdateUnloadPriority(i->first,priority);
265 SignalImageRead(i->first,false);
268 /// Already requested : change the priority
269 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
270 pitl->SetPriority(priority);
272 if (pitl->Index()>=0)
275 mQueue.upsort(pitl->Index());
277 // Not read but not in queue = being read = ok
285 // Never requested before or unloaded
286 ImageToLoadPtr pitl = new ImageToLoad(user,filename,priority);
291 //=====================================================================
293 //=====================================================================
294 void MultiThreadImageReader::OnMultiThreadImageReaderEvent
295 (const std::string& filename,
296 MultiThreadImageReaderUser::EventType e,
299 if ((e==MultiThreadImageReaderUser::ImageLoaded) &&
300 (filename == mRequestedFilename))
302 mRequestedImage = image;
304 else if (e==MultiThreadImageReaderUser::ThreadedReaderStarted)
306 mNumberOfThreadedReadersRunning++;
307 // std::cout << "#TR=" << mNumberOfThreadedReadersRunning << std::endl;
309 else if (e==MultiThreadImageReaderUser::ThreadedReaderStopped)
312 mNumberOfThreadedReadersRunning--;
313 // std::cout << "#TR=" << mNumberOfThreadedReadersRunning << std::endl;
316 //=====================================================================
318 //=====================================================================
319 vtkImageData* MultiThreadImageReader::GetImage(const std::string& filename)
322 // std::cout << "** MultiThreadImageReader::GetImage('"<<filename<<"')"
327 // wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
329 // std::cout << "** MultiThreadImageReader::GetImage('"<<filename
333 // if (mNumberOfThreadedReadersRunning==0)
334 // if (mThreadedImageReaderList.size()==0)
337 ImageToLoad itl(this,filename);
338 ImageMapType::iterator i = mImages.find(&itl);
339 if (i!=mImages.end())
341 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
343 if (pitl->GetImage() != 0)
346 UpdateUnloadPriority(pitl,
347 GetMaximalPriorityWithoutLocking()+1);
348 return pitl->GetImage();
351 ImageToLoadPtr pitl = new ImageToLoad(this,filename,0);
353 pitl->SetImage(mReader->ReadImage(filename));
354 UpdateUnloadPriority(pitl,
355 GetMaximalPriorityWithoutLocking()+1);
356 return pitl->GetImage();
360 mRequestedFilename = filename;
362 ImageToLoad itl(this,filename);
363 ImageMapType::iterator i = mImages.find(&itl);
364 if (i!=mImages.end())
366 // Already inserted in queue
367 if (i->first->GetImage() != 0)
369 // Already read : ok : return it
370 return i->first->GetImage();
372 /// Already requested : change the priority
373 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
374 pitl->SetPriority( GetMaximalPriorityWithoutLocking() + 1 );
375 pitl->SetUser( this );
377 if (pitl->Index()>=0)
380 mQueue.upsort(pitl->Index());
382 // Not read but not in queue = being read = ok
385 pitl->SetUser( this );
391 // Never requested before or unloaded
392 ImageToLoadPtr pitl =
393 new ImageToLoad(this,filename,
394 GetMaximalPriorityWithoutLocking() + 1);
402 // std::cout << "Waiting..."<<std::endl;
405 // Waiting that it is read
409 // std::cout << n++ << std::endl;
413 // wxMutexLocker lock(mMutex);
414 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex());
415 if (mRequestedImage!=0)
417 return mRequestedImage;
426 //=====================================================================
428 //=====================================================================
429 void MultiThreadImageReader::SignalImageRead(ImageToLoadPtr p,
433 // std::cout << "MultiThreadImageReader::SignalImageRead" <<std::endl;
434 // std::cout << "this="<<this <<std::endl;
435 // std::cout << "user="<<p->GetUser() <<std::endl;
437 if ( p->GetUser() == this )
438 GetMultiThreadImageReaderUserMutex().Unlock();
440 p->GetUser()->MultiThreadImageReaderSendEvent
442 MultiThreadImageReaderUser::ImageLoaded,
446 AN ATTEMPT TO UNLOAD OLDEST IMAGE IF EXCEEDED A CERTAIN MEMORY QUOTA
450 GimmickMessage(5,"Image '"<<p->GetFilename()<<"' read"<<std::endl);
452 // wxMutexLocker lock(GetMultiThreadImageReaderUserMutex());
454 mUnloadQueue.insert(p);
455 p->GetImage()->UpdateInformation();
456 p->GetImage()->PropagateUpdateExtent();
457 long ImMem = p->GetImage()->GetEstimatedMemorySize();
460 GimmickMessage(5,"==> Image in memory = "<<mUnloadQueue.size()<<std::endl);
461 GimmickMessage(5,"==> Total mem = "<<mTotalMem<<" Ko"<<std::endl);
465 while (mTotalMem > mTotalMemMax)
468 " ! Exceeded max of "
469 << mTotalMemMax << " Ko : unloading oldest image ... "
471 if ( mUnloadQueue.size() <= 1 )
474 " Only one image : cannot load AND unload it !!"
479 ImageToLoadPtr unload = mUnloadQueue.remove_top();
480 MultiThreadImageReaderUser* user = unload->GetUser();
483 if ((user!=0)&&(user!=this))
485 user->GetMultiThreadImageReaderUserMutex().Lock();
489 std::string filename = unload->GetFilename();
491 GimmickMessage(5,"'" << filename << "'" << std::endl);
492 mTotalMem -= unload->GetImage()->GetEstimatedMemorySize();
494 GimmickMessage(5," ==> Total mem = "<<mTotalMem<<" Ko "<<std::endl);
498 // std::cout << "unlock..."<<std::endl;
499 // user->GetMultiThreadImageReaderUserMutex().Unlock();
500 // std::cout << "event"<<std::endl;
501 user->MultiThreadImageReaderSendEvent
503 MultiThreadImageReaderUser::ImageUnloaded,
505 // std::cout << "event ok"<<std::endl;
508 if (unload->Index()>=0)
510 // GimmickMessage(5,"still in queue"<<std::endl);
512 unload->Index() = -1;
515 ImageMapType::iterator it = mImages.find(unload);
516 if (it!=mImages.end())
520 // std::cout << "delete..."<<std::endl;
522 // std::cout << "delete ok."<<std::endl;
526 //=====================================================================
528 //=====================================================================
529 int MultiThreadImageReader::GetMaximalPriority()
531 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
532 return GetMaximalPriorityWithoutLocking();
534 //=====================================================================
537 //=====================================================================
538 int MultiThreadImageReader::GetMaximalPriorityWithoutLocking()
543 max = mQueue.top()->GetPriority();
545 if (mUnloadQueue.size()>0)
547 int max2 = mUnloadQueue.top()->GetPriority();
548 if (max2>max) max=max2;
552 //=====================================================================
555 //=====================================================================
556 //=====================================================================
557 //=====================================================================
558 //=====================================================================
560 //=====================================================================
561 void* ThreadedImageReader::Entry()
563 // std::cout << "### Thread "<<GetCurrentId()<<"::Entry()"
566 mMultiThreadImageReader->MultiThreadImageReaderSendEvent
568 MultiThreadImageReaderUser::ThreadedReaderStarted,
571 // While was not deleted
572 while (!TestDestroy())
574 //std::cout << "### Thread "<<GetCurrentId()<<" still alive" << std::endl;
577 mMultiThreadImageReader->MultiThreadImageReaderEventLock();
580 if (mMultiThreadImageReader->mQueue.size()>0)
582 MultiThreadImageReader::ImageToLoadPtr i =
583 mMultiThreadImageReader->mQueue.remove_top();
585 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();
589 // std::cout << "### Thread "<<GetCurrentId()<<" : reading '"
590 // << i->GetFilename() << "'" << std::endl;
593 vtkImageData* im = Read(i->GetFilename());
595 // Store it in the map
596 mMultiThreadImageReader->MultiThreadImageReaderEventLock();
598 MultiThreadImageReader::ImageToLoad itl(0,i->GetFilename());
599 MultiThreadImageReader::ImageMapType::iterator it =
600 mMultiThreadImageReader->mImages.find(&itl);
601 MultiThreadImageReader::ImageToLoadPtr
602 pitl = const_cast<MultiThreadImageReader::ImageToLoadPtr>
605 mMultiThreadImageReader->SignalImageRead(pitl,true);//i->GetFilename());
606 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock(); //mMutex.Unlock();
608 // std::cout << "### Thread "<<GetCurrentId()<<" : reading '"
609 // << i->GetFilename() << "' : DONE" << std::endl;
614 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();
616 // Wait a little to avoid blocking
620 // std::cout << "### Thread "<<GetCurrentId()<<" stopping"
625 //=====================================================================
627 //=====================================================================
628 void ThreadedImageReader::OnExit()
630 mMultiThreadImageReader->MultiThreadImageReaderSendEvent
632 MultiThreadImageReaderUser::ThreadedReaderStopped,
635 //=====================================================================
637 //=====================================================================
638 vtkImageData* ThreadedImageReader::Read(const std::string& filename)
640 return mReader.ReadImage(filename);
642 //=====================================================================
644 } // namespace creaImageIO