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;
51 //=====================================================================
54 //=====================================================================
55 MultiThreadImageReader::MultiThreadImageReader(int number_of_threads)
56 : //mDoNotSignal(false),
61 // std::cout << "#### MultiThreadImageReader::MultiThreadImageReader("
62 // << " #threads= " << number_of_threads <<" )"<<std::endl;
65 for (int i=0; i<number_of_threads; i++)
67 //ThreadedImageReader* t = new ThreadedImageReader(this);
68 boost::shared_ptr<ThreadedImageReader> t(new ThreadedImageReader(this), ThreadedImageReader::deleter());
69 mThreadedImageReaderList.push_back(t);
70 std::cout << " ===> Thread "<<i
71 <<" successfully added"<< std::endl;
73 mNumberOfThreadedReadersRunning = 0;
75 mQueue.set(mComparator);
78 // no thread : alloc self reader
79 // if (number_of_threads==0)
81 mReader = new ImageReader();
84 //=====================================================================
87 //=====================================================================
88 bool MultiThreadImageReader::Start()
91 // std::cout << "#### MultiThreadImageReader::Start()"
93 if (mNumberOfThreadedReadersRunning > 0) return true;
95 ThreadedImageReaderListType::iterator i;
96 for (i =mThreadedImageReaderList.begin();
97 i!=mThreadedImageReaderList.end();
101 if ( (*i)->Run() != wxTHREAD_NO_ERROR )
103 std::cout << "ERROR starting a thread"<< std::endl;
108 std::cout << " ===> Thread "<<(*i)->GetCurrentId()
109 <<" successfully created"<< std::endl;
113 wxMutexLocker locker(GetMultiThreadImageReaderUserMutex());
114 // std::cout << "EO Start : #Threads running = "
115 // << mNumberOfThreadedReadersRunning<<std::endl;
119 //=====================================================================
121 //=====================================================================
122 void MultiThreadImageReader::Stop()
124 // std::cout << "#### MultiThreadImageReader::Stop()"
126 // std::cout << "Sending stop order to the threads..."<<std::endl;
128 ThreadedImageReaderListType::iterator i;
129 for (i =mThreadedImageReaderList.begin();
130 i!=mThreadedImageReaderList.end();
132 { std::cout << " ===> Thread "<<(*i)->GetCurrentId()
133 <<" successfully stopped"<< std::endl;
140 // mThreadedImageReaderList.clear();
141 // Wait a little to be sure that all threads have stopped
142 // A better way to do this ?
143 // wxMilliSleep(1000);
144 // New method : the threads generate a stop event when they have finished
145 // We wait until all threads have stopped
146 // std::cout << "Waiting for stop signals..."<<std::endl;
153 wxMutexLocker locker(GetMultiThreadImageReaderUserMutex());
154 // std::cout << "#Threads running = "
155 // << mNumberOfThreadedReadersRunning<<std::endl;
156 // Break if all readers have stopped
157 if (mNumberOfThreadedReadersRunning <= 0)
164 // std::cout << "All threads stopped : OK "<<std::endl;
166 ImageMapType::iterator j;
167 for (j =mImages.begin();
176 //=====================================================================
178 //=====================================================================
179 MultiThreadImageReader::~MultiThreadImageReader()
181 // std::cout << "#### MultiThreadImageReader::~MultiThreadImageReader()"
184 if (mReader) delete mReader;
185 mThreadedImageReaderList.clear();
187 //=====================================================================
189 //=====================================================================
190 void MultiThreadImageReader::UpdateUnloadPriority(ImageToLoadPtr p,
193 // not in unload queue : ciao
194 if (p->UnloadIndex()<0) return;
195 int old_prio = p->GetPriority();
196 if (priority > old_prio)
198 p->SetPriority(priority);
199 mUnloadQueue.downsort(p->UnloadIndex());
201 else if ( old_prio > priority )
203 p->SetPriority(priority);
204 mUnloadQueue.upsort(p->UnloadIndex());
207 //=====================================================================
209 //=====================================================================
210 void MultiThreadImageReader::Request( MultiThreadImageReaderUser* user,
211 const std::string& filename,
214 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
216 if (mNumberOfThreadedReadersRunning==0)
217 // if (mThreadedImageReaderList.size()==0)
219 // no detached reader : use self reader
220 ImageToLoad itl(user,filename);
221 ImageMapType::iterator i = mImages.find(&itl);
222 if (i!=mImages.end())
224 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
226 if (pitl->GetImage() != 0)
230 UpdateUnloadPriority(pitl,priority);
231 SignalImageRead(pitl,false);
232 return; // pitl->GetImage();
235 ImageToLoadPtr pitl = new ImageToLoad(user,filename,0);
237 pitl->SetImage(mReader->ReadImage(filename));
238 UpdateUnloadPriority(pitl,priority);
239 SignalImageRead(pitl,true);
240 // return pitl->GetImage();
244 ImageToLoad itl(user,filename);
245 ImageMapType::iterator i = mImages.find(&itl);
246 if (i!=mImages.end())
249 if (i->first->GetImage() != 0)
251 // Already read : ok :signal the user
252 UpdateUnloadPriority(i->first,priority);
253 SignalImageRead(i->first,false);
256 /// Already requested : change the priority
257 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
258 pitl->SetPriority(priority);
260 if (pitl->Index()>=0)
263 mQueue.upsort(pitl->Index());
265 // Not read but not in queue = being read = ok
273 // Never requested before or unloaded
274 ImageToLoadPtr pitl = new ImageToLoad(user,filename,priority);
279 //=====================================================================
281 //=====================================================================
282 void MultiThreadImageReader::OnMultiThreadImageReaderEvent
283 (const std::string& filename,
284 MultiThreadImageReaderUser::EventType e,
287 if ((e==MultiThreadImageReaderUser::ImageLoaded) &&
288 (filename == mRequestedFilename))
290 mRequestedImage = image;
292 else if (e==MultiThreadImageReaderUser::ThreadedReaderStarted)
294 mNumberOfThreadedReadersRunning++;
295 // std::cout << "#TR=" << mNumberOfThreadedReadersRunning << std::endl;
297 else if (e==MultiThreadImageReaderUser::ThreadedReaderStopped)
300 mNumberOfThreadedReadersRunning--;
301 // std::cout << "#TR=" << mNumberOfThreadedReadersRunning << std::endl;
304 //=====================================================================
306 //=====================================================================
307 vtkImageData* MultiThreadImageReader::GetImage(const std::string& filename)
310 // std::cout << "** MultiThreadImageReader::GetImage('"<<filename<<"')"
315 // wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
317 // std::cout << "** MultiThreadImageReader::GetImage('"<<filename
321 // if (mNumberOfThreadedReadersRunning==0)
322 // if (mThreadedImageReaderList.size()==0)
325 ImageToLoad itl(this,filename);
326 ImageMapType::iterator i = mImages.find(&itl);
327 if (i!=mImages.end())
329 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
331 if (pitl->GetImage() != 0)
334 UpdateUnloadPriority(pitl,
335 GetMaximalPriorityWithoutLocking()+1);
336 return pitl->GetImage();
339 ImageToLoadPtr pitl = new ImageToLoad(this,filename,0);
341 pitl->SetImage(mReader->ReadImage(filename));
342 UpdateUnloadPriority(pitl,
343 GetMaximalPriorityWithoutLocking()+1);
344 return pitl->GetImage();
348 mRequestedFilename = filename;
350 ImageToLoad itl(this,filename);
351 ImageMapType::iterator i = mImages.find(&itl);
352 if (i!=mImages.end())
354 // Already inserted in queue
355 if (i->first->GetImage() != 0)
357 // Already read : ok : return it
358 return i->first->GetImage();
360 /// Already requested : change the priority
361 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
362 pitl->SetPriority( GetMaximalPriorityWithoutLocking() + 1 );
363 pitl->SetUser( this );
365 if (pitl->Index()>=0)
368 mQueue.upsort(pitl->Index());
370 // Not read but not in queue = being read = ok
373 pitl->SetUser( this );
379 // Never requested before or unloaded
380 ImageToLoadPtr pitl =
381 new ImageToLoad(this,filename,
382 GetMaximalPriorityWithoutLocking() + 1);
390 // std::cout << "Waiting..."<<std::endl;
393 // Waiting that it is read
397 // std::cout << n++ << std::endl;
401 // wxMutexLocker lock(mMutex);
402 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex());
403 if (mRequestedImage!=0)
405 return mRequestedImage;
414 //=====================================================================
416 //=====================================================================
417 void MultiThreadImageReader::SignalImageRead(ImageToLoadPtr p,
421 // std::cout << "MultiThreadImageReader::SignalImageRead" <<std::endl;
422 // std::cout << "this="<<this <<std::endl;
423 // std::cout << "user="<<p->GetUser() <<std::endl;
425 if ( p->GetUser() == this )
426 GetMultiThreadImageReaderUserMutex().Unlock();
428 p->GetUser()->MultiThreadImageReaderSendEvent
430 MultiThreadImageReaderUser::ImageLoaded,
434 AN ATTEMPT TO UNLOAD OLDEST IMAGE IF EXCEEDED A CERTAIN MEMORY QUOTA
438 GimmickMessage(5,"Image '"<<p->GetFilename()<<"' read"<<std::endl);
440 // wxMutexLocker lock(GetMultiThreadImageReaderUserMutex());
442 mUnloadQueue.insert(p);
443 p->GetImage()->UpdateInformation();
444 p->GetImage()->PropagateUpdateExtent();
445 long ImMem = p->GetImage()->GetEstimatedMemorySize();
448 GimmickMessage(5,"==> Image in memory = "<<mUnloadQueue.size()<<std::endl);
449 GimmickMessage(5,"==> Total mem = "<<mTotalMem<<" Ko"<<std::endl);
453 while (mTotalMem > mTotalMemMax)
456 " ! Exceeded max of "
457 << mTotalMemMax << " Ko : unloading oldest image ... "
459 if ( mUnloadQueue.size() <= 1 )
462 " Only one image : cannot load AND unload it !!"
467 ImageToLoadPtr unload = mUnloadQueue.remove_top();
468 MultiThreadImageReaderUser* user = unload->GetUser();
471 if ((user!=0)&&(user!=this))
473 user->GetMultiThreadImageReaderUserMutex().Lock();
477 std::string filename = unload->GetFilename();
479 GimmickMessage(5,"'" << filename << "'" << std::endl);
480 mTotalMem -= unload->GetImage()->GetEstimatedMemorySize();
482 GimmickMessage(5," ==> Total mem = "<<mTotalMem<<" Ko "<<std::endl);
486 // std::cout << "unlock..."<<std::endl;
487 // user->GetMultiThreadImageReaderUserMutex().Unlock();
488 // std::cout << "event"<<std::endl;
489 user->MultiThreadImageReaderSendEvent
491 MultiThreadImageReaderUser::ImageUnloaded,
493 // std::cout << "event ok"<<std::endl;
496 if (unload->Index()>=0)
498 // GimmickMessage(5,"still in queue"<<std::endl);
500 unload->Index() = -1;
503 ImageMapType::iterator it = mImages.find(unload);
504 if (it!=mImages.end())
508 // std::cout << "delete..."<<std::endl;
510 // std::cout << "delete ok."<<std::endl;
514 //=====================================================================
516 //=====================================================================
517 int MultiThreadImageReader::GetMaximalPriority()
519 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
520 return GetMaximalPriorityWithoutLocking();
522 //=====================================================================
525 //=====================================================================
526 int MultiThreadImageReader::GetMaximalPriorityWithoutLocking()
531 max = mQueue.top()->GetPriority();
533 if (mUnloadQueue.size()>0)
535 int max2 = mUnloadQueue.top()->GetPriority();
536 if (max2>max) max=max2;
540 //=====================================================================
543 //=====================================================================
544 //=====================================================================
545 //=====================================================================
546 //=====================================================================
548 //=====================================================================
549 void* ThreadedImageReader::Entry()
551 // std::cout << "### Thread "<<GetCurrentId()<<"::Entry()"
554 mMultiThreadImageReader->MultiThreadImageReaderSendEvent
556 MultiThreadImageReaderUser::ThreadedReaderStarted,
559 // While was not deleted
560 while (!TestDestroy())
562 //std::cout << "### Thread "<<GetCurrentId()<<" still alive" << std::endl;
565 mMultiThreadImageReader->MultiThreadImageReaderEventLock();
568 if (mMultiThreadImageReader->mQueue.size()>0)
570 MultiThreadImageReader::ImageToLoadPtr i =
571 mMultiThreadImageReader->mQueue.remove_top();
573 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();
577 // std::cout << "### Thread "<<GetCurrentId()<<" : reading '"
578 // << i->GetFilename() << "'" << std::endl;
581 vtkImageData* im = Read(i->GetFilename());
583 // Store it in the map
584 mMultiThreadImageReader->MultiThreadImageReaderEventLock();
586 MultiThreadImageReader::ImageToLoad itl(0,i->GetFilename());
587 MultiThreadImageReader::ImageMapType::iterator it =
588 mMultiThreadImageReader->mImages.find(&itl);
589 MultiThreadImageReader::ImageToLoadPtr
590 pitl = const_cast<MultiThreadImageReader::ImageToLoadPtr>
593 mMultiThreadImageReader->SignalImageRead(pitl,true);//i->GetFilename());
594 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock(); //mMutex.Unlock();
596 // std::cout << "### Thread "<<GetCurrentId()<<" : reading '"
597 // << i->GetFilename() << "' : DONE" << std::endl;
602 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();
604 // Wait a little to avoid blocking
608 // std::cout << "### Thread "<<GetCurrentId()<<" stopping"
613 //=====================================================================
615 //=====================================================================
616 void ThreadedImageReader::OnExit()
618 mMultiThreadImageReader->MultiThreadImageReaderSendEvent
620 MultiThreadImageReaderUser::ThreadedReaderStopped,
623 //=====================================================================
625 //=====================================================================
626 vtkImageData* ThreadedImageReader::Read(const std::string& filename)
628 return mReader.ReadImage(filename);
630 //=====================================================================
632 } // namespace creaImageIO