1 #include <creaImageIOMultiThreadImageReader.h>
2 #include <creaImageIOImageReader.h>
8 //=====================================================================
9 void MultiThreadImageReaderUser::MultiThreadImageReaderSendEvent
10 ( const std::string& filename,
14 wxMutexLocker lock(mMultiThreadImageReaderUserMutex);
15 this->OnMultiThreadImageReaderEvent(filename,type,image);
17 //=====================================================================
19 //=====================================================================
20 class ThreadedImageReader: public wxThread
23 ThreadedImageReader(MultiThreadImageReader* tir) :
24 mMultiThreadImageReader(tir)
30 vtkImageData* Read(const std::string& filename);
35 MultiThreadImageReader* mMultiThreadImageReader;
37 //=====================================================================
40 //=====================================================================
41 MultiThreadImageReader::MultiThreadImageReader(int number_of_threads)
42 : //mDoNotSignal(false),
47 // std::cout << "#### MultiThreadImageReader::MultiThreadImageReader("
48 // << " #threads= " << number_of_threads <<" )"<<std::endl;
51 for (int i=0; i<number_of_threads; i++)
53 ThreadedImageReader* t = new ThreadedImageReader(this);
54 mThreadedImageReaderList.push_back(t);
56 mNumberOfThreadedReadersRunning = 0;
58 mQueue.set(mComparator);
61 // no thread : alloc self reader
62 if (number_of_threads==0)
64 mReader = new ImageReader();
67 //=====================================================================
70 //=====================================================================
71 bool MultiThreadImageReader::Start()
74 // std::cout << "#### MultiThreadImageReader::Start()"
76 ThreadedImageReaderListType::iterator i;
77 for (i =mThreadedImageReaderList.begin();
78 i!=mThreadedImageReaderList.end();
82 if ( (*i)->Run() != wxTHREAD_NO_ERROR )
84 std::cout << "ERROR starting a thread"<< std::endl;
89 // std::cout << " ===> Thread "<<(*i)->GetCurrentId()
90 // <<" successfully created"<< std::endl;
94 wxMutexLocker locker(GetMultiThreadImageReaderUserMutex());
95 // std::cout << "EO Start : #Threads running = "
96 // << mNumberOfThreadedReadersRunning<<std::endl;
100 //=====================================================================
102 //=====================================================================
103 void MultiThreadImageReader::Stop()
105 // std::cout << "#### MultiThreadImageReader::Stop()"
107 // std::cout << "Sending stop order to the threads..."<<std::endl;
109 ThreadedImageReaderListType::iterator i;
110 for (i =mThreadedImageReaderList.begin();
111 i!=mThreadedImageReaderList.end();
116 mThreadedImageReaderList.clear();
117 // Wait a little to be sure that all threads have stopped
118 // A better way to do this ?
119 // wxMilliSleep(1000);
120 // New method : the threads generate a stop event when they have finished
121 // We wait until all threads have stopped
122 // std::cout << "Waiting for stop signals..."<<std::endl;
129 wxMutexLocker locker(GetMultiThreadImageReaderUserMutex());
130 // std::cout << "#Threads running = "
131 // << mNumberOfThreadedReadersRunning<<std::endl;
132 // Break if all readers have stopped
133 if (mNumberOfThreadedReadersRunning <= 0)
140 // std::cout << "All threads stopped : OK "<<std::endl;
142 ImageMapType::iterator j;
143 for (j =mImages.begin();
152 //=====================================================================
154 //=====================================================================
155 MultiThreadImageReader::~MultiThreadImageReader()
157 // std::cout << "#### MultiThreadImageReader::~MultiThreadImageReader()"
160 if (mReader) delete mReader;
162 //=====================================================================
164 //=====================================================================
165 void MultiThreadImageReader::UpdateUnloadPriority(ImageToLoadPtr p,
168 // not in unload queue : ciao
169 if (p->UnloadIndex()<0) return;
170 int old_prio = p->GetPriority();
171 if (priority > old_prio)
173 p->SetPriority(priority);
174 mUnloadQueue.downsort(p->UnloadIndex());
176 else if ( old_prio > priority )
178 p->SetPriority(priority);
179 mUnloadQueue.upsort(p->UnloadIndex());
182 //=====================================================================
184 //=====================================================================
185 void MultiThreadImageReader::Request( MultiThreadImageReaderUser* user,
186 const std::string& filename,
189 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
191 if (mThreadedImageReaderList.size()==0)
193 // no detached reader : use self reader
194 ImageToLoad itl(user,filename);
195 ImageMapType::iterator i = mImages.find(&itl);
196 if (i!=mImages.end())
198 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
200 if (pitl->GetImage() != 0)
204 UpdateUnloadPriority(pitl,priority);
205 SignalImageRead(pitl,false);
206 return; // pitl->GetImage();
209 ImageToLoadPtr pitl = new ImageToLoad(user,filename,0);
211 pitl->SetImage(mReader->Read(filename));
212 UpdateUnloadPriority(pitl,priority);
213 SignalImageRead(pitl,true);
214 // return pitl->GetImage();
219 ImageToLoad itl(user,filename);
220 ImageMapType::iterator i = mImages.find(&itl);
221 if (i!=mImages.end())
224 if (i->first->GetImage() != 0)
226 // Already read : ok :signal the user
227 UpdateUnloadPriority(i->first,priority);
228 SignalImageRead(i->first,false);
231 /// Already requested : change the priority
232 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
233 pitl->SetPriority(priority);
235 if (pitl->Index()>=0)
238 mQueue.upsort(pitl->Index());
240 // Not read but not in queue = being read = ok
248 // Never requested before or unloaded
249 ImageToLoadPtr pitl = new ImageToLoad(user,filename,priority);
254 //=====================================================================
256 //=====================================================================
257 void MultiThreadImageReader::OnMultiThreadImageReaderEvent
258 (const std::string& filename,
259 MultiThreadImageReaderUser::EventType e,
262 if ((e==MultiThreadImageReaderUser::ImageLoaded) &&
263 (filename == mRequestedFilename))
265 mRequestedImage = image;
267 else if (e==MultiThreadImageReaderUser::ThreadedReaderStarted)
269 mNumberOfThreadedReadersRunning++;
270 // std::cout << "#TR=" << mNumberOfThreadedReadersRunning << std::endl;
272 else if (e==MultiThreadImageReaderUser::ThreadedReaderStopped)
274 mNumberOfThreadedReadersRunning--;
275 // std::cout << "#TR=" << mNumberOfThreadedReadersRunning << std::endl;
278 //=====================================================================
280 //=====================================================================
281 vtkImageData* MultiThreadImageReader::GetImage(const std::string& filename)
284 // std::cout << "** MultiThreadImageReader::GetImage('"<<filename<<"')"
289 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
291 if (mThreadedImageReaderList.size()==0)
293 ImageToLoad itl(this,filename);
294 ImageMapType::iterator i = mImages.find(&itl);
295 if (i!=mImages.end())
297 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
299 if (pitl->GetImage() != 0)
302 UpdateUnloadPriority(pitl,
303 GetMaximalPriorityWithoutLocking()+1);
304 return pitl->GetImage();
307 ImageToLoadPtr pitl = new ImageToLoad(this,filename,0);
309 pitl->SetImage(mReader->Read(filename));
310 UpdateUnloadPriority(pitl,
311 GetMaximalPriorityWithoutLocking()+1);
312 return pitl->GetImage();
315 mRequestedFilename = filename;
317 ImageToLoad itl(this,filename);
318 ImageMapType::iterator i = mImages.find(&itl);
319 if (i!=mImages.end())
321 // Already inserted in queue
322 if (i->first->GetImage() != 0)
324 // Already read : ok : return it
325 return i->first->GetImage();
327 /// Already requested : change the priority
328 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
329 pitl->SetPriority( GetMaximalPriorityWithoutLocking() + 1 );
330 pitl->SetUser( this );
332 if (pitl->Index()>=0)
335 mQueue.upsort(pitl->Index());
337 // Not read but not in queue = being read = ok
340 pitl->SetUser( this );
346 // Never requested before or unloaded
347 ImageToLoadPtr pitl =
348 new ImageToLoad(this,filename,
349 GetMaximalPriorityWithoutLocking() + 1);
356 // std::cout << "Waiting..."<<std::endl;
358 // Waiting that it is read
362 // std::cout << n++ << std::endl;
366 // wxMutexLocker lock(mMutex);
367 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex());
368 if (mRequestedImage!=0)
370 return mRequestedImage;
379 //=====================================================================
381 //=====================================================================
382 void MultiThreadImageReader::SignalImageRead(ImageToLoadPtr p,
385 // std::cout << "MultiThreadImageReader::SignalImageRead" <<std::endl;
386 // std::cout << "this="<<this <<std::endl;
387 // std::cout << "user="<<p->GetUser() <<std::endl;
389 if ( p->GetUser() == this )
390 GetMultiThreadImageReaderUserMutex().Unlock();
392 p->GetUser()->MultiThreadImageReaderSendEvent
394 MultiThreadImageReaderUser::ImageLoaded,
398 AN ATTEMPT TO UNLOAD OLDEST IMAGE IF EXCEEDED A CERTAIN MEMORY QUOTA
403 // wxMutexLocker lock(GetMultiThreadImageReaderUserMutex());
405 mUnloadQueue.insert(p);
406 p->GetImage()->UpdateInformation();
407 p->GetImage()->PropagateUpdateExtent();
408 long ImMem = p->GetImage()->GetEstimatedMemorySize();
410 // std::cout << " ==> Total mem = "<<mTotalMem<<" Ko"<<std::endl;
411 while (mTotalMem > mTotalMemMax)
414 // <<" ! Exceeded max of "
415 // << mTotalMemMax << " : unloading oldest image ... "
417 if ( mUnloadQueue.size() <= 1 )
419 // std::cout << "Only one image : cannot load AND unload it !!"
424 ImageToLoadPtr unload = mUnloadQueue.remove_top();
425 MultiThreadImageReaderUser* user = unload->GetUser();
427 if ((user!=0)&&(user!=this))
429 user->GetMultiThreadImageReaderUserMutex().Lock();
433 // std::cout << "'" << unload->GetFilename() << "'" << std::endl;
434 mTotalMem -= unload->GetImage()->GetEstimatedMemorySize();
435 // std::cout << " ==> Total mem = "<<mTotalMem<<" Ko "<<std::endl;
438 std::string filename = unload->GetFilename();
439 if (unload->Index()>=0)
441 // std::cout << "still in queue"<<std::endl;
443 unload->Index() = -1;
446 ImageMapType::iterator it = mImages.find(unload);
447 if (it!=mImages.end())
451 // std::cout << "delete..."<<std::endl;
453 // std::cout << "delete ok."<<std::endl;
457 // std::cout << "unlock..."<<std::endl;
458 user->GetMultiThreadImageReaderUserMutex().Unlock();
459 // std::cout << "event"<<std::endl;
460 user->MultiThreadImageReaderSendEvent
462 MultiThreadImageReaderUser::ImageUnloaded,
464 // std::cout << "event ok"<<std::endl;
471 //=====================================================================
473 //=====================================================================
474 int MultiThreadImageReader::GetMaximalPriority()
476 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
477 return GetMaximalPriorityWithoutLocking();
479 //=====================================================================
482 //=====================================================================
483 int MultiThreadImageReader::GetMaximalPriorityWithoutLocking()
488 max = mQueue.top()->GetPriority();
490 if (mUnloadQueue.size()>0)
492 int max2 = mUnloadQueue.top()->GetPriority();
493 if (max2>max) max=max2;
497 //=====================================================================
500 //=====================================================================
501 //=====================================================================
502 //=====================================================================
503 //=====================================================================
505 //=====================================================================
506 void* ThreadedImageReader::Entry()
508 // std::cout << "### Thread "<<GetCurrentId()<<"::Entry()"
511 mMultiThreadImageReader->MultiThreadImageReaderSendEvent
513 MultiThreadImageReaderUser::ThreadedReaderStarted,
516 // While was not deleted
517 while (!TestDestroy())
519 // std::cout << "### Thread "<<GetCurrentId()<<" waiting for image"
523 mMultiThreadImageReader->MultiThreadImageReaderEventLock();
526 if (mMultiThreadImageReader->mQueue.size()>0)
528 MultiThreadImageReader::ImageToLoadPtr i =
529 mMultiThreadImageReader->mQueue.remove_top();
531 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();
535 // std::cout << "### Thread "<<GetCurrentId()<<" : reading '"
536 // << i->GetFilename() << "'" << std::endl;
539 vtkImageData* im = Read(i->GetFilename());
541 // Store it in the map
542 mMultiThreadImageReader->MultiThreadImageReaderEventLock();
544 MultiThreadImageReader::ImageToLoad itl(0,i->GetFilename());
545 MultiThreadImageReader::ImageMapType::iterator it =
546 mMultiThreadImageReader->mImages.find(&itl);
547 MultiThreadImageReader::ImageToLoadPtr
548 pitl = const_cast<MultiThreadImageReader::ImageToLoadPtr>
551 mMultiThreadImageReader->SignalImageRead(pitl,true);//i->GetFilename());
552 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock(); //mMutex.Unlock();
554 // std::cout << "### Thread "<<GetCurrentId()<<" : reading '"
555 // << i->GetFilename() << "' : DONE" << std::endl;
560 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();
562 // Wait a little to avoid blocking
566 // std::cout << "### Thread "<<GetCurrentId()<<" stopping"
571 //=====================================================================
573 //=====================================================================
574 void ThreadedImageReader::OnExit()
576 mMultiThreadImageReader->MultiThreadImageReaderSendEvent
578 MultiThreadImageReaderUser::ThreadedReaderStopped,
581 //=====================================================================
583 //=====================================================================
584 vtkImageData* ThreadedImageReader::Read(const std::string& filename)
586 return mReader.Read(filename);
588 //=====================================================================
590 } // namespace creaImageIO