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);
37 MultiThreadImageReader* mMultiThreadImageReader;
40 //=====================================================================
43 //=====================================================================
44 MultiThreadImageReader::MultiThreadImageReader(int number_of_threads)
45 : //mDoNotSignal(false),
50 // std::cout << "#### MultiThreadImageReader::MultiThreadImageReader("
51 // << " #threads= " << number_of_threads <<" )"<<std::endl;
54 for (int i=0; i<number_of_threads; i++)
56 //ThreadedImageReader* t = new ThreadedImageReader(this);
57 boost::shared_ptr<ThreadedImageReader> t(new ThreadedImageReader(this));
58 mThreadedImageReaderList.push_back(t);
59 std::cout << " ===> Thread "<<i
60 <<" successfully added"<< std::endl;
62 mNumberOfThreadedReadersRunning = 0;
64 mQueue.set(mComparator);
67 // no thread : alloc self reader
68 // if (number_of_threads==0)
70 mReader = new ImageReader();
73 //=====================================================================
76 //=====================================================================
77 bool MultiThreadImageReader::Start()
80 // std::cout << "#### MultiThreadImageReader::Start()"
82 if (mNumberOfThreadedReadersRunning > 0) return true;
84 ThreadedImageReaderListType::iterator i;
85 for (i =mThreadedImageReaderList.begin();
86 i!=mThreadedImageReaderList.end();
90 if ( (*i)->Run() != wxTHREAD_NO_ERROR )
92 std::cout << "ERROR starting a thread"<< std::endl;
97 std::cout << " ===> Thread "<<(*i)->GetCurrentId()
98 <<" successfully created"<< std::endl;
102 wxMutexLocker locker(GetMultiThreadImageReaderUserMutex());
103 // std::cout << "EO Start : #Threads running = "
104 // << mNumberOfThreadedReadersRunning<<std::endl;
108 //=====================================================================
110 //=====================================================================
111 void MultiThreadImageReader::Stop()
113 // std::cout << "#### MultiThreadImageReader::Stop()"
115 // std::cout << "Sending stop order to the threads..."<<std::endl;
117 ThreadedImageReaderListType::iterator i;
118 for (i =mThreadedImageReaderList.begin();
119 i!=mThreadedImageReaderList.end();
121 { std::cout << " ===> Thread "<<(*i)->GetCurrentId()
122 <<" successfully stopped"<< std::endl;
128 mThreadedImageReaderList.clear();
129 // Wait a little to be sure that all threads have stopped
130 // A better way to do this ?
131 // wxMilliSleep(1000);
132 // New method : the threads generate a stop event when they have finished
133 // We wait until all threads have stopped
134 // std::cout << "Waiting for stop signals..."<<std::endl;
141 wxMutexLocker locker(GetMultiThreadImageReaderUserMutex());
142 // std::cout << "#Threads running = "
143 // << mNumberOfThreadedReadersRunning<<std::endl;
144 // Break if all readers have stopped
145 if (mNumberOfThreadedReadersRunning <= 0)
152 // std::cout << "All threads stopped : OK "<<std::endl;
154 ImageMapType::iterator j;
155 for (j =mImages.begin();
164 //=====================================================================
166 //=====================================================================
167 MultiThreadImageReader::~MultiThreadImageReader()
169 // std::cout << "#### MultiThreadImageReader::~MultiThreadImageReader()"
172 if (mReader) delete mReader;
173 mThreadedImageReaderList.clear();
175 //=====================================================================
177 //=====================================================================
178 void MultiThreadImageReader::UpdateUnloadPriority(ImageToLoadPtr p,
181 // not in unload queue : ciao
182 if (p->UnloadIndex()<0) return;
183 int old_prio = p->GetPriority();
184 if (priority > old_prio)
186 p->SetPriority(priority);
187 mUnloadQueue.downsort(p->UnloadIndex());
189 else if ( old_prio > priority )
191 p->SetPriority(priority);
192 mUnloadQueue.upsort(p->UnloadIndex());
195 //=====================================================================
197 //=====================================================================
198 void MultiThreadImageReader::Request( MultiThreadImageReaderUser* user,
199 const std::string& filename,
202 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
204 if (mNumberOfThreadedReadersRunning==0)
205 // if (mThreadedImageReaderList.size()==0)
207 // no detached reader : use self reader
208 ImageToLoad itl(user,filename);
209 ImageMapType::iterator i = mImages.find(&itl);
210 if (i!=mImages.end())
212 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
214 if (pitl->GetImage() != 0)
218 UpdateUnloadPriority(pitl,priority);
219 SignalImageRead(pitl,false);
220 return; // pitl->GetImage();
223 ImageToLoadPtr pitl = new ImageToLoad(user,filename,0);
225 pitl->SetImage(mReader->ReadImage(filename));
226 UpdateUnloadPriority(pitl,priority);
227 SignalImageRead(pitl,true);
228 // return pitl->GetImage();
233 ImageToLoad itl(user,filename);
234 ImageMapType::iterator i = mImages.find(&itl);
235 if (i!=mImages.end())
238 if (i->first->GetImage() != 0)
240 // Already read : ok :signal the user
241 UpdateUnloadPriority(i->first,priority);
242 SignalImageRead(i->first,false);
245 /// Already requested : change the priority
246 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
247 pitl->SetPriority(priority);
249 if (pitl->Index()>=0)
252 mQueue.upsort(pitl->Index());
254 // Not read but not in queue = being read = ok
262 // Never requested before or unloaded
263 ImageToLoadPtr pitl = new ImageToLoad(user,filename,priority);
268 //=====================================================================
270 //=====================================================================
271 void MultiThreadImageReader::OnMultiThreadImageReaderEvent
272 (const std::string& filename,
273 MultiThreadImageReaderUser::EventType e,
276 if ((e==MultiThreadImageReaderUser::ImageLoaded) &&
277 (filename == mRequestedFilename))
279 mRequestedImage = image;
281 else if (e==MultiThreadImageReaderUser::ThreadedReaderStarted)
283 mNumberOfThreadedReadersRunning++;
284 // std::cout << "#TR=" << mNumberOfThreadedReadersRunning << std::endl;
286 else if (e==MultiThreadImageReaderUser::ThreadedReaderStopped)
289 mNumberOfThreadedReadersRunning--;
290 // std::cout << "#TR=" << mNumberOfThreadedReadersRunning << std::endl;
293 //=====================================================================
295 //=====================================================================
296 vtkImageData* MultiThreadImageReader::GetImage(const std::string& filename)
299 // std::cout << "** MultiThreadImageReader::GetImage('"<<filename<<"')"
304 // wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
306 // std::cout << "** MultiThreadImageReader::GetImage('"<<filename
310 // if (mNumberOfThreadedReadersRunning==0)
311 // if (mThreadedImageReaderList.size()==0)
314 ImageToLoad itl(this,filename);
315 ImageMapType::iterator i = mImages.find(&itl);
316 if (i!=mImages.end())
318 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
320 if (pitl->GetImage() != 0)
323 UpdateUnloadPriority(pitl,
324 GetMaximalPriorityWithoutLocking()+1);
325 return pitl->GetImage();
328 ImageToLoadPtr pitl = new ImageToLoad(this,filename,0);
330 pitl->SetImage(mReader->ReadImage(filename));
331 UpdateUnloadPriority(pitl,
332 GetMaximalPriorityWithoutLocking()+1);
333 return pitl->GetImage();
337 mRequestedFilename = filename;
339 ImageToLoad itl(this,filename);
340 ImageMapType::iterator i = mImages.find(&itl);
341 if (i!=mImages.end())
343 // Already inserted in queue
344 if (i->first->GetImage() != 0)
346 // Already read : ok : return it
347 return i->first->GetImage();
349 /// Already requested : change the priority
350 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
351 pitl->SetPriority( GetMaximalPriorityWithoutLocking() + 1 );
352 pitl->SetUser( this );
354 if (pitl->Index()>=0)
357 mQueue.upsort(pitl->Index());
359 // Not read but not in queue = being read = ok
362 pitl->SetUser( this );
368 // Never requested before or unloaded
369 ImageToLoadPtr pitl =
370 new ImageToLoad(this,filename,
371 GetMaximalPriorityWithoutLocking() + 1);
379 // std::cout << "Waiting..."<<std::endl;
382 // Waiting that it is read
386 // std::cout << n++ << std::endl;
390 // wxMutexLocker lock(mMutex);
391 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex());
392 if (mRequestedImage!=0)
394 return mRequestedImage;
403 //=====================================================================
405 //=====================================================================
406 void MultiThreadImageReader::SignalImageRead(ImageToLoadPtr p,
410 // std::cout << "MultiThreadImageReader::SignalImageRead" <<std::endl;
411 // std::cout << "this="<<this <<std::endl;
412 // std::cout << "user="<<p->GetUser() <<std::endl;
414 if ( p->GetUser() == this )
415 GetMultiThreadImageReaderUserMutex().Unlock();
417 p->GetUser()->MultiThreadImageReaderSendEvent
419 MultiThreadImageReaderUser::ImageLoaded,
423 AN ATTEMPT TO UNLOAD OLDEST IMAGE IF EXCEEDED A CERTAIN MEMORY QUOTA
427 GimmickMessage(5,"Image '"<<p->GetFilename()<<"' read"<<std::endl);
429 // wxMutexLocker lock(GetMultiThreadImageReaderUserMutex());
431 mUnloadQueue.insert(p);
432 p->GetImage()->UpdateInformation();
433 p->GetImage()->PropagateUpdateExtent();
434 long ImMem = p->GetImage()->GetEstimatedMemorySize();
437 GimmickMessage(5,"==> Image in memory = "<<mUnloadQueue.size()<<std::endl);
438 GimmickMessage(5,"==> Total mem = "<<mTotalMem<<" Ko"<<std::endl);
442 while (mTotalMem > mTotalMemMax)
445 " ! Exceeded max of "
446 << mTotalMemMax << " Ko : unloading oldest image ... "
448 if ( mUnloadQueue.size() <= 1 )
451 " Only one image : cannot load AND unload it !!"
456 ImageToLoadPtr unload = mUnloadQueue.remove_top();
457 MultiThreadImageReaderUser* user = unload->GetUser();
460 if ((user!=0)&&(user!=this))
462 user->GetMultiThreadImageReaderUserMutex().Lock();
466 std::string filename = unload->GetFilename();
468 GimmickMessage(5,"'" << filename << "'" << std::endl);
469 mTotalMem -= unload->GetImage()->GetEstimatedMemorySize();
471 GimmickMessage(5," ==> Total mem = "<<mTotalMem<<" Ko "<<std::endl);
476 // std::cout << "unlock..."<<std::endl;
477 // user->GetMultiThreadImageReaderUserMutex().Unlock();
478 // std::cout << "event"<<std::endl;
479 user->MultiThreadImageReaderSendEvent
481 MultiThreadImageReaderUser::ImageUnloaded,
483 // std::cout << "event ok"<<std::endl;
487 if (unload->Index()>=0)
489 // GimmickMessage(5,"still in queue"<<std::endl);
491 unload->Index() = -1;
494 ImageMapType::iterator it = mImages.find(unload);
495 if (it!=mImages.end())
499 // std::cout << "delete..."<<std::endl;
501 // std::cout << "delete ok."<<std::endl;
507 //=====================================================================
509 //=====================================================================
510 int MultiThreadImageReader::GetMaximalPriority()
512 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
513 return GetMaximalPriorityWithoutLocking();
515 //=====================================================================
518 //=====================================================================
519 int MultiThreadImageReader::GetMaximalPriorityWithoutLocking()
524 max = mQueue.top()->GetPriority();
526 if (mUnloadQueue.size()>0)
528 int max2 = mUnloadQueue.top()->GetPriority();
529 if (max2>max) max=max2;
533 //=====================================================================
536 //=====================================================================
537 //=====================================================================
538 //=====================================================================
539 //=====================================================================
541 //=====================================================================
542 void* ThreadedImageReader::Entry()
544 // std::cout << "### Thread "<<GetCurrentId()<<"::Entry()"
547 mMultiThreadImageReader->MultiThreadImageReaderSendEvent
549 MultiThreadImageReaderUser::ThreadedReaderStarted,
552 // While was not deleted
553 while (!TestDestroy())
555 //std::cout << "### Thread "<<GetCurrentId()<<" still alive" << std::endl;
558 mMultiThreadImageReader->MultiThreadImageReaderEventLock();
561 if (mMultiThreadImageReader->mQueue.size()>0)
563 MultiThreadImageReader::ImageToLoadPtr i =
564 mMultiThreadImageReader->mQueue.remove_top();
566 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();
570 // std::cout << "### Thread "<<GetCurrentId()<<" : reading '"
571 // << i->GetFilename() << "'" << std::endl;
574 vtkImageData* im = Read(i->GetFilename());
576 // Store it in the map
577 mMultiThreadImageReader->MultiThreadImageReaderEventLock();
579 MultiThreadImageReader::ImageToLoad itl(0,i->GetFilename());
580 MultiThreadImageReader::ImageMapType::iterator it =
581 mMultiThreadImageReader->mImages.find(&itl);
582 MultiThreadImageReader::ImageToLoadPtr
583 pitl = const_cast<MultiThreadImageReader::ImageToLoadPtr>
586 mMultiThreadImageReader->SignalImageRead(pitl,true);//i->GetFilename());
587 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock(); //mMutex.Unlock();
589 // std::cout << "### Thread "<<GetCurrentId()<<" : reading '"
590 // << i->GetFilename() << "' : DONE" << std::endl;
595 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();
597 // Wait a little to avoid blocking
601 // std::cout << "### Thread "<<GetCurrentId()<<" stopping"
606 //=====================================================================
608 //=====================================================================
609 void ThreadedImageReader::OnExit()
611 mMultiThreadImageReader->MultiThreadImageReaderSendEvent
613 MultiThreadImageReaderUser::ThreadedReaderStopped,
616 //=====================================================================
618 //=====================================================================
619 vtkImageData* ThreadedImageReader::Read(const std::string& filename)
621 return mReader.ReadImage(filename);
623 //=====================================================================
625 } // namespace creaImageIO