1 #include <creaImageIOMultiThreadImageReader.h>
2 #include <creaImageIOImageReader.h>
4 #include <creaImageIOSystem.h>
10 //=====================================================================
11 void MultiThreadImageReaderUser::MultiThreadImageReaderSendEvent
12 ( const std::string& filename,
16 wxMutexLocker lock(mMultiThreadImageReaderUserMutex);
18 this->OnMultiThreadImageReaderEvent(filename,type,image);
20 //=====================================================================
22 //=====================================================================
23 class ThreadedImageReader: public wxThread
26 ThreadedImageReader(MultiThreadImageReader* tir) :
27 mMultiThreadImageReader(tir)
33 vtkImageData* Read(const std::string& filename);
37 void operator()(ThreadedImageReader* p)
42 friend struct deleter;
47 MultiThreadImageReader* mMultiThreadImageReader;
52 //=====================================================================
55 //=====================================================================
56 MultiThreadImageReader::MultiThreadImageReader(int number_of_threads)
57 : //mDoNotSignal(false),
62 // std::cout << "#### MultiThreadImageReader::MultiThreadImageReader("
63 // << " #threads= " << number_of_threads <<" )"<<std::endl;
66 for (int i=0; i<number_of_threads; i++)
68 //ThreadedImageReader* t = new ThreadedImageReader(this);
69 boost::shared_ptr<ThreadedImageReader> t(new ThreadedImageReader(this), ThreadedImageReader::deleter());
70 mThreadedImageReaderList.push_back(t);
71 std::cout << " ===> Thread "<<i
72 <<" successfully added"<< std::endl;
74 mNumberOfThreadedReadersRunning = 0;
76 mQueue.set(mComparator);
79 // no thread : alloc self reader
80 // if (number_of_threads==0)
82 mReader = new ImageReader();
85 //=====================================================================
88 //=====================================================================
89 bool MultiThreadImageReader::Start()
92 // std::cout << "#### MultiThreadImageReader::Start()"
94 if (mNumberOfThreadedReadersRunning > 0) return true;
96 ThreadedImageReaderListType::iterator i;
97 for (i =mThreadedImageReaderList.begin();
98 i!=mThreadedImageReaderList.end();
102 if ( (*i)->Run() != wxTHREAD_NO_ERROR )
104 std::cout << "ERROR starting a thread"<< std::endl;
109 std::cout << " ===> Thread "<<(*i)->GetCurrentId()
110 <<" successfully created"<< std::endl;
114 wxMutexLocker locker(GetMultiThreadImageReaderUserMutex());
115 // std::cout << "EO Start : #Threads running = "
116 // << mNumberOfThreadedReadersRunning<<std::endl;
120 //=====================================================================
122 //=====================================================================
123 void MultiThreadImageReader::Stop()
125 // std::cout << "#### MultiThreadImageReader::Stop()"
127 // std::cout << "Sending stop order to the threads..."<<std::endl;
129 ThreadedImageReaderListType::iterator i;
130 for (i =mThreadedImageReaderList.begin();
131 i!=mThreadedImageReaderList.end();
133 { std::cout << " ===> Thread "<<(*i)->GetCurrentId()
134 <<" successfully stopped"<< std::endl;
141 // mThreadedImageReaderList.clear();
142 // Wait a little to be sure that all threads have stopped
143 // A better way to do this ?
144 // wxMilliSleep(1000);
145 // New method : the threads generate a stop event when they have finished
146 // We wait until all threads have stopped
147 // std::cout << "Waiting for stop signals..."<<std::endl;
154 wxMutexLocker locker(GetMultiThreadImageReaderUserMutex());
155 // std::cout << "#Threads running = "
156 // << mNumberOfThreadedReadersRunning<<std::endl;
157 // Break if all readers have stopped
158 if (mNumberOfThreadedReadersRunning <= 0)
165 // std::cout << "All threads stopped : OK "<<std::endl;
167 ImageMapType::iterator j;
168 for (j =mImages.begin();
177 //=====================================================================
179 //=====================================================================
180 MultiThreadImageReader::~MultiThreadImageReader()
182 // std::cout << "#### MultiThreadImageReader::~MultiThreadImageReader()"
185 if (mReader) delete mReader;
186 mThreadedImageReaderList.clear();
188 //=====================================================================
190 //=====================================================================
191 void MultiThreadImageReader::UpdateUnloadPriority(ImageToLoadPtr p,
194 // not in unload queue : ciao
195 if (p->UnloadIndex()<0) return;
196 int old_prio = p->GetPriority();
197 if (priority > old_prio)
199 p->SetPriority(priority);
200 mUnloadQueue.downsort(p->UnloadIndex());
202 else if ( old_prio > priority )
204 p->SetPriority(priority);
205 mUnloadQueue.upsort(p->UnloadIndex());
208 //=====================================================================
210 //=====================================================================
211 void MultiThreadImageReader::Request( MultiThreadImageReaderUser* user,
212 const std::string& filename,
215 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
217 if (mNumberOfThreadedReadersRunning==0)
218 // if (mThreadedImageReaderList.size()==0)
220 // no detached reader : use self reader
221 ImageToLoad itl(user,filename);
222 ImageMapType::iterator i = mImages.find(&itl);
223 if (i!=mImages.end())
225 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
227 if (pitl->GetImage() != 0)
231 UpdateUnloadPriority(pitl,priority);
232 SignalImageRead(pitl,false);
233 return; // pitl->GetImage();
236 ImageToLoadPtr pitl = new ImageToLoad(user,filename,0);
238 pitl->SetImage(mReader->ReadImage(filename));
239 UpdateUnloadPriority(pitl,priority);
240 SignalImageRead(pitl,true);
241 // return pitl->GetImage();
246 ImageToLoad itl(user,filename);
247 ImageMapType::iterator i = mImages.find(&itl);
248 if (i!=mImages.end())
251 if (i->first->GetImage() != 0)
253 // Already read : ok :signal the user
254 UpdateUnloadPriority(i->first,priority);
255 SignalImageRead(i->first,false);
258 /// Already requested : change the priority
259 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
260 pitl->SetPriority(priority);
262 if (pitl->Index()>=0)
265 mQueue.upsort(pitl->Index());
267 // Not read but not in queue = being read = ok
275 // Never requested before or unloaded
276 ImageToLoadPtr pitl = new ImageToLoad(user,filename,priority);
281 //=====================================================================
283 //=====================================================================
284 void MultiThreadImageReader::OnMultiThreadImageReaderEvent
285 (const std::string& filename,
286 MultiThreadImageReaderUser::EventType e,
289 if ((e==MultiThreadImageReaderUser::ImageLoaded) &&
290 (filename == mRequestedFilename))
292 mRequestedImage = image;
294 else if (e==MultiThreadImageReaderUser::ThreadedReaderStarted)
296 mNumberOfThreadedReadersRunning++;
297 // std::cout << "#TR=" << mNumberOfThreadedReadersRunning << std::endl;
299 else if (e==MultiThreadImageReaderUser::ThreadedReaderStopped)
302 mNumberOfThreadedReadersRunning--;
303 // std::cout << "#TR=" << mNumberOfThreadedReadersRunning << std::endl;
306 //=====================================================================
308 //=====================================================================
309 vtkImageData* MultiThreadImageReader::GetImage(const std::string& filename)
312 // std::cout << "** MultiThreadImageReader::GetImage('"<<filename<<"')"
317 // wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
319 // std::cout << "** MultiThreadImageReader::GetImage('"<<filename
323 // if (mNumberOfThreadedReadersRunning==0)
324 // if (mThreadedImageReaderList.size()==0)
327 ImageToLoad itl(this,filename);
328 ImageMapType::iterator i = mImages.find(&itl);
329 if (i!=mImages.end())
331 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
333 if (pitl->GetImage() != 0)
336 UpdateUnloadPriority(pitl,
337 GetMaximalPriorityWithoutLocking()+1);
338 return pitl->GetImage();
341 ImageToLoadPtr pitl = new ImageToLoad(this,filename,0);
343 pitl->SetImage(mReader->ReadImage(filename));
344 UpdateUnloadPriority(pitl,
345 GetMaximalPriorityWithoutLocking()+1);
346 return pitl->GetImage();
350 mRequestedFilename = filename;
352 ImageToLoad itl(this,filename);
353 ImageMapType::iterator i = mImages.find(&itl);
354 if (i!=mImages.end())
356 // Already inserted in queue
357 if (i->first->GetImage() != 0)
359 // Already read : ok : return it
360 return i->first->GetImage();
362 /// Already requested : change the priority
363 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
364 pitl->SetPriority( GetMaximalPriorityWithoutLocking() + 1 );
365 pitl->SetUser( this );
367 if (pitl->Index()>=0)
370 mQueue.upsort(pitl->Index());
372 // Not read but not in queue = being read = ok
375 pitl->SetUser( this );
381 // Never requested before or unloaded
382 ImageToLoadPtr pitl =
383 new ImageToLoad(this,filename,
384 GetMaximalPriorityWithoutLocking() + 1);
392 // std::cout << "Waiting..."<<std::endl;
395 // Waiting that it is read
399 // std::cout << n++ << std::endl;
403 // wxMutexLocker lock(mMutex);
404 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex());
405 if (mRequestedImage!=0)
407 return mRequestedImage;
416 //=====================================================================
418 //=====================================================================
419 void MultiThreadImageReader::SignalImageRead(ImageToLoadPtr p,
423 // std::cout << "MultiThreadImageReader::SignalImageRead" <<std::endl;
424 // std::cout << "this="<<this <<std::endl;
425 // std::cout << "user="<<p->GetUser() <<std::endl;
427 if ( p->GetUser() == this )
428 GetMultiThreadImageReaderUserMutex().Unlock();
430 p->GetUser()->MultiThreadImageReaderSendEvent
432 MultiThreadImageReaderUser::ImageLoaded,
436 AN ATTEMPT TO UNLOAD OLDEST IMAGE IF EXCEEDED A CERTAIN MEMORY QUOTA
440 GimmickMessage(5,"Image '"<<p->GetFilename()<<"' read"<<std::endl);
442 // wxMutexLocker lock(GetMultiThreadImageReaderUserMutex());
444 mUnloadQueue.insert(p);
445 p->GetImage()->UpdateInformation();
446 p->GetImage()->PropagateUpdateExtent();
447 long ImMem = p->GetImage()->GetEstimatedMemorySize();
450 GimmickMessage(5,"==> Image in memory = "<<mUnloadQueue.size()<<std::endl);
451 GimmickMessage(5,"==> Total mem = "<<mTotalMem<<" Ko"<<std::endl);
455 while (mTotalMem > mTotalMemMax)
458 " ! Exceeded max of "
459 << mTotalMemMax << " Ko : unloading oldest image ... "
461 if ( mUnloadQueue.size() <= 1 )
464 " Only one image : cannot load AND unload it !!"
469 ImageToLoadPtr unload = mUnloadQueue.remove_top();
470 MultiThreadImageReaderUser* user = unload->GetUser();
473 if ((user!=0)&&(user!=this))
475 user->GetMultiThreadImageReaderUserMutex().Lock();
479 std::string filename = unload->GetFilename();
481 GimmickMessage(5,"'" << filename << "'" << std::endl);
482 mTotalMem -= unload->GetImage()->GetEstimatedMemorySize();
484 GimmickMessage(5," ==> Total mem = "<<mTotalMem<<" Ko "<<std::endl);
489 // std::cout << "unlock..."<<std::endl;
490 // user->GetMultiThreadImageReaderUserMutex().Unlock();
491 // std::cout << "event"<<std::endl;
492 user->MultiThreadImageReaderSendEvent
494 MultiThreadImageReaderUser::ImageUnloaded,
496 // std::cout << "event ok"<<std::endl;
500 if (unload->Index()>=0)
502 // GimmickMessage(5,"still in queue"<<std::endl);
504 unload->Index() = -1;
507 ImageMapType::iterator it = mImages.find(unload);
508 if (it!=mImages.end())
512 // std::cout << "delete..."<<std::endl;
514 // std::cout << "delete ok."<<std::endl;
520 //=====================================================================
522 //=====================================================================
523 int MultiThreadImageReader::GetMaximalPriority()
525 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
526 return GetMaximalPriorityWithoutLocking();
528 //=====================================================================
531 //=====================================================================
532 int MultiThreadImageReader::GetMaximalPriorityWithoutLocking()
537 max = mQueue.top()->GetPriority();
539 if (mUnloadQueue.size()>0)
541 int max2 = mUnloadQueue.top()->GetPriority();
542 if (max2>max) max=max2;
546 //=====================================================================
549 //=====================================================================
550 //=====================================================================
551 //=====================================================================
552 //=====================================================================
554 //=====================================================================
555 void* ThreadedImageReader::Entry()
557 // std::cout << "### Thread "<<GetCurrentId()<<"::Entry()"
560 mMultiThreadImageReader->MultiThreadImageReaderSendEvent
562 MultiThreadImageReaderUser::ThreadedReaderStarted,
565 // While was not deleted
566 while (!TestDestroy())
568 //std::cout << "### Thread "<<GetCurrentId()<<" still alive" << std::endl;
571 mMultiThreadImageReader->MultiThreadImageReaderEventLock();
574 if (mMultiThreadImageReader->mQueue.size()>0)
576 MultiThreadImageReader::ImageToLoadPtr i =
577 mMultiThreadImageReader->mQueue.remove_top();
579 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();
583 // std::cout << "### Thread "<<GetCurrentId()<<" : reading '"
584 // << i->GetFilename() << "'" << std::endl;
587 vtkImageData* im = Read(i->GetFilename());
589 // Store it in the map
590 mMultiThreadImageReader->MultiThreadImageReaderEventLock();
592 MultiThreadImageReader::ImageToLoad itl(0,i->GetFilename());
593 MultiThreadImageReader::ImageMapType::iterator it =
594 mMultiThreadImageReader->mImages.find(&itl);
595 MultiThreadImageReader::ImageToLoadPtr
596 pitl = const_cast<MultiThreadImageReader::ImageToLoadPtr>
599 mMultiThreadImageReader->SignalImageRead(pitl,true);//i->GetFilename());
600 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock(); //mMutex.Unlock();
602 // std::cout << "### Thread "<<GetCurrentId()<<" : reading '"
603 // << i->GetFilename() << "' : DONE" << std::endl;
608 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();
610 // Wait a little to avoid blocking
614 // std::cout << "### Thread "<<GetCurrentId()<<" stopping"
619 //=====================================================================
621 //=====================================================================
622 void ThreadedImageReader::OnExit()
624 mMultiThreadImageReader->MultiThreadImageReaderSendEvent
626 MultiThreadImageReaderUser::ThreadedReaderStopped,
629 //=====================================================================
631 //=====================================================================
632 vtkImageData* ThreadedImageReader::Read(const std::string& filename)
634 return mReader.ReadImage(filename);
636 //=====================================================================
638 } // namespace creaImageIO