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);
16 this->OnMultiThreadImageReaderEvent(filename,type,image);
18 //=====================================================================
20 //=====================================================================
21 class ThreadedImageReader: public wxThread
24 ThreadedImageReader(MultiThreadImageReader* tir) :
25 mMultiThreadImageReader(tir)
31 vtkImageData* Read(const std::string& filename);
36 MultiThreadImageReader* mMultiThreadImageReader;
39 //=====================================================================
42 //=====================================================================
43 MultiThreadImageReader::MultiThreadImageReader(int number_of_threads)
44 : //mDoNotSignal(false),
49 // std::cout << "#### MultiThreadImageReader::MultiThreadImageReader("
50 // << " #threads= " << number_of_threads <<" )"<<std::endl;
53 for (int i=0; i<number_of_threads; i++)
55 ThreadedImageReader* t = new ThreadedImageReader(this);
56 mThreadedImageReaderList.push_back(t);
58 mNumberOfThreadedReadersRunning = 0;
60 mQueue.set(mComparator);
63 // no thread : alloc self reader
64 // if (number_of_threads==0)
66 mReader = new ImageReader();
69 //=====================================================================
72 //=====================================================================
73 bool MultiThreadImageReader::Start()
76 // std::cout << "#### MultiThreadImageReader::Start()"
78 if (mNumberOfThreadedReadersRunning > 0) return true;
80 ThreadedImageReaderListType::iterator i;
81 for (i =mThreadedImageReaderList.begin();
82 i!=mThreadedImageReaderList.end();
86 if ( (*i)->Run() != wxTHREAD_NO_ERROR )
88 std::cout << "ERROR starting a thread"<< std::endl;
93 // std::cout << " ===> Thread "<<(*i)->GetCurrentId()
94 // <<" successfully created"<< std::endl;
98 wxMutexLocker locker(GetMultiThreadImageReaderUserMutex());
99 // std::cout << "EO Start : #Threads running = "
100 // << mNumberOfThreadedReadersRunning<<std::endl;
104 //=====================================================================
106 //=====================================================================
107 void MultiThreadImageReader::Stop()
109 // std::cout << "#### MultiThreadImageReader::Stop()"
111 // std::cout << "Sending stop order to the threads..."<<std::endl;
113 ThreadedImageReaderListType::iterator i;
114 for (i =mThreadedImageReaderList.begin();
115 i!=mThreadedImageReaderList.end();
123 mThreadedImageReaderList.clear();
124 // Wait a little to be sure that all threads have stopped
125 // A better way to do this ?
126 // wxMilliSleep(1000);
127 // New method : the threads generate a stop event when they have finished
128 // We wait until all threads have stopped
129 // std::cout << "Waiting for stop signals..."<<std::endl;
136 wxMutexLocker locker(GetMultiThreadImageReaderUserMutex());
137 // std::cout << "#Threads running = "
138 // << mNumberOfThreadedReadersRunning<<std::endl;
139 // Break if all readers have stopped
140 if (mNumberOfThreadedReadersRunning <= 0)
147 // std::cout << "All threads stopped : OK "<<std::endl;
149 ImageMapType::iterator j;
150 for (j =mImages.begin();
159 //=====================================================================
161 //=====================================================================
162 MultiThreadImageReader::~MultiThreadImageReader()
164 // std::cout << "#### MultiThreadImageReader::~MultiThreadImageReader()"
167 if (mReader) delete mReader;
169 //=====================================================================
171 //=====================================================================
172 void MultiThreadImageReader::UpdateUnloadPriority(ImageToLoadPtr p,
175 // not in unload queue : ciao
176 if (p->UnloadIndex()<0) return;
177 int old_prio = p->GetPriority();
178 if (priority > old_prio)
180 p->SetPriority(priority);
181 mUnloadQueue.downsort(p->UnloadIndex());
183 else if ( old_prio > priority )
185 p->SetPriority(priority);
186 mUnloadQueue.upsort(p->UnloadIndex());
189 //=====================================================================
191 //=====================================================================
192 void MultiThreadImageReader::Request( MultiThreadImageReaderUser* user,
193 const std::string& filename,
196 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
198 if (mNumberOfThreadedReadersRunning==0)
199 // if (mThreadedImageReaderList.size()==0)
201 // no detached reader : use self reader
202 ImageToLoad itl(user,filename);
203 ImageMapType::iterator i = mImages.find(&itl);
204 if (i!=mImages.end())
206 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
208 if (pitl->GetImage() != 0)
212 UpdateUnloadPriority(pitl,priority);
213 SignalImageRead(pitl,false);
214 return; // pitl->GetImage();
217 ImageToLoadPtr pitl = new ImageToLoad(user,filename,0);
219 pitl->SetImage(mReader->ReadImage(filename));
220 UpdateUnloadPriority(pitl,priority);
221 SignalImageRead(pitl,true);
222 // return pitl->GetImage();
227 ImageToLoad itl(user,filename);
228 ImageMapType::iterator i = mImages.find(&itl);
229 if (i!=mImages.end())
232 if (i->first->GetImage() != 0)
234 // Already read : ok :signal the user
235 UpdateUnloadPriority(i->first,priority);
236 SignalImageRead(i->first,false);
239 /// Already requested : change the priority
240 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
241 pitl->SetPriority(priority);
243 if (pitl->Index()>=0)
246 mQueue.upsort(pitl->Index());
248 // Not read but not in queue = being read = ok
256 // Never requested before or unloaded
257 ImageToLoadPtr pitl = new ImageToLoad(user,filename,priority);
262 //=====================================================================
264 //=====================================================================
265 void MultiThreadImageReader::OnMultiThreadImageReaderEvent
266 (const std::string& filename,
267 MultiThreadImageReaderUser::EventType e,
270 if ((e==MultiThreadImageReaderUser::ImageLoaded) &&
271 (filename == mRequestedFilename))
273 mRequestedImage = image;
275 else if (e==MultiThreadImageReaderUser::ThreadedReaderStarted)
277 mNumberOfThreadedReadersRunning++;
278 // std::cout << "#TR=" << mNumberOfThreadedReadersRunning << std::endl;
280 else if (e==MultiThreadImageReaderUser::ThreadedReaderStopped)
282 mNumberOfThreadedReadersRunning--;
283 // std::cout << "#TR=" << mNumberOfThreadedReadersRunning << std::endl;
286 //=====================================================================
288 //=====================================================================
289 vtkImageData* MultiThreadImageReader::GetImage(const std::string& filename)
292 // std::cout << "** MultiThreadImageReader::GetImage('"<<filename<<"')"
297 // wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
299 // std::cout << "** MultiThreadImageReader::GetImage('"<<filename
303 // if (mNumberOfThreadedReadersRunning==0)
304 // if (mThreadedImageReaderList.size()==0)
307 ImageToLoad itl(this,filename);
308 ImageMapType::iterator i = mImages.find(&itl);
309 if (i!=mImages.end())
311 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
313 if (pitl->GetImage() != 0)
316 UpdateUnloadPriority(pitl,
317 GetMaximalPriorityWithoutLocking()+1);
318 return pitl->GetImage();
321 ImageToLoadPtr pitl = new ImageToLoad(this,filename,0);
323 pitl->SetImage(mReader->ReadImage(filename));
324 UpdateUnloadPriority(pitl,
325 GetMaximalPriorityWithoutLocking()+1);
326 return pitl->GetImage();
330 mRequestedFilename = filename;
332 ImageToLoad itl(this,filename);
333 ImageMapType::iterator i = mImages.find(&itl);
334 if (i!=mImages.end())
336 // Already inserted in queue
337 if (i->first->GetImage() != 0)
339 // Already read : ok : return it
340 return i->first->GetImage();
342 /// Already requested : change the priority
343 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
344 pitl->SetPriority( GetMaximalPriorityWithoutLocking() + 1 );
345 pitl->SetUser( this );
347 if (pitl->Index()>=0)
350 mQueue.upsort(pitl->Index());
352 // Not read but not in queue = being read = ok
355 pitl->SetUser( this );
361 // Never requested before or unloaded
362 ImageToLoadPtr pitl =
363 new ImageToLoad(this,filename,
364 GetMaximalPriorityWithoutLocking() + 1);
372 // std::cout << "Waiting..."<<std::endl;
375 // Waiting that it is read
379 // std::cout << n++ << std::endl;
383 // wxMutexLocker lock(mMutex);
384 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex());
385 if (mRequestedImage!=0)
387 return mRequestedImage;
396 //=====================================================================
398 //=====================================================================
399 void MultiThreadImageReader::SignalImageRead(ImageToLoadPtr p,
403 // std::cout << "MultiThreadImageReader::SignalImageRead" <<std::endl;
404 // std::cout << "this="<<this <<std::endl;
405 // std::cout << "user="<<p->GetUser() <<std::endl;
407 if ( p->GetUser() == this )
408 GetMultiThreadImageReaderUserMutex().Unlock();
410 p->GetUser()->MultiThreadImageReaderSendEvent
412 MultiThreadImageReaderUser::ImageLoaded,
416 AN ATTEMPT TO UNLOAD OLDEST IMAGE IF EXCEEDED A CERTAIN MEMORY QUOTA
420 GimmickMessage(5,"Image '"<<p->GetFilename()<<"' read"<<std::endl);
422 // wxMutexLocker lock(GetMultiThreadImageReaderUserMutex());
424 mUnloadQueue.insert(p);
425 p->GetImage()->UpdateInformation();
426 p->GetImage()->PropagateUpdateExtent();
427 long ImMem = p->GetImage()->GetEstimatedMemorySize();
430 GimmickMessage(5,"==> Image in memory = "<<mUnloadQueue.size()<<std::endl);
431 GimmickMessage(5,"==> Total mem = "<<mTotalMem<<" Ko"<<std::endl);
435 while (mTotalMem > mTotalMemMax)
438 " ! Exceeded max of "
439 << mTotalMemMax << " Ko : unloading oldest image ... "
441 if ( mUnloadQueue.size() <= 1 )
444 " Only one image : cannot load AND unload it !!"
449 ImageToLoadPtr unload = mUnloadQueue.remove_top();
450 MultiThreadImageReaderUser* user = unload->GetUser();
453 if ((user!=0)&&(user!=this))
455 user->GetMultiThreadImageReaderUserMutex().Lock();
459 std::string filename = unload->GetFilename();
461 GimmickMessage(5,"'" << filename << "'" << std::endl);
462 mTotalMem -= unload->GetImage()->GetEstimatedMemorySize();
464 GimmickMessage(5," ==> Total mem = "<<mTotalMem<<" Ko "<<std::endl);
469 // std::cout << "unlock..."<<std::endl;
470 // user->GetMultiThreadImageReaderUserMutex().Unlock();
471 // std::cout << "event"<<std::endl;
472 user->MultiThreadImageReaderSendEvent
474 MultiThreadImageReaderUser::ImageUnloaded,
476 // std::cout << "event ok"<<std::endl;
480 if (unload->Index()>=0)
482 // GimmickMessage(5,"still in queue"<<std::endl);
484 unload->Index() = -1;
487 ImageMapType::iterator it = mImages.find(unload);
488 if (it!=mImages.end())
492 // std::cout << "delete..."<<std::endl;
494 // std::cout << "delete ok."<<std::endl;
500 //=====================================================================
502 //=====================================================================
503 int MultiThreadImageReader::GetMaximalPriority()
505 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
506 return GetMaximalPriorityWithoutLocking();
508 //=====================================================================
511 //=====================================================================
512 int MultiThreadImageReader::GetMaximalPriorityWithoutLocking()
517 max = mQueue.top()->GetPriority();
519 if (mUnloadQueue.size()>0)
521 int max2 = mUnloadQueue.top()->GetPriority();
522 if (max2>max) max=max2;
526 //=====================================================================
529 //=====================================================================
530 //=====================================================================
531 //=====================================================================
532 //=====================================================================
534 //=====================================================================
535 void* ThreadedImageReader::Entry()
537 // std::cout << "### Thread "<<GetCurrentId()<<"::Entry()"
540 mMultiThreadImageReader->MultiThreadImageReaderSendEvent
542 MultiThreadImageReaderUser::ThreadedReaderStarted,
545 // While was not deleted
546 while (!TestDestroy())
548 // std::cout << "### Thread "<<GetCurrentId()<<" waiting for image"
552 mMultiThreadImageReader->MultiThreadImageReaderEventLock();
555 if (mMultiThreadImageReader->mQueue.size()>0)
557 MultiThreadImageReader::ImageToLoadPtr i =
558 mMultiThreadImageReader->mQueue.remove_top();
560 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();
564 // std::cout << "### Thread "<<GetCurrentId()<<" : reading '"
565 // << i->GetFilename() << "'" << std::endl;
568 vtkImageData* im = Read(i->GetFilename());
570 // Store it in the map
571 mMultiThreadImageReader->MultiThreadImageReaderEventLock();
573 MultiThreadImageReader::ImageToLoad itl(0,i->GetFilename());
574 MultiThreadImageReader::ImageMapType::iterator it =
575 mMultiThreadImageReader->mImages.find(&itl);
576 MultiThreadImageReader::ImageToLoadPtr
577 pitl = const_cast<MultiThreadImageReader::ImageToLoadPtr>
580 mMultiThreadImageReader->SignalImageRead(pitl,true);//i->GetFilename());
581 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock(); //mMutex.Unlock();
583 // std::cout << "### Thread "<<GetCurrentId()<<" : reading '"
584 // << i->GetFilename() << "' : DONE" << std::endl;
589 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();
591 // Wait a little to avoid blocking
595 // std::cout << "### Thread "<<GetCurrentId()<<" stopping"
600 //=====================================================================
602 //=====================================================================
603 void ThreadedImageReader::OnExit()
605 mMultiThreadImageReader->MultiThreadImageReaderSendEvent
607 MultiThreadImageReaderUser::ThreadedReaderStopped,
610 //=====================================================================
612 //=====================================================================
613 vtkImageData* ThreadedImageReader::Read(const std::string& filename)
615 return mReader.ReadImage(filename);
617 //=====================================================================
619 } // namespace creaImageIO