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;
38 //=====================================================================
41 //=====================================================================
42 MultiThreadImageReader::MultiThreadImageReader(int number_of_threads)
43 : //mDoNotSignal(false),
48 // std::cout << "#### MultiThreadImageReader::MultiThreadImageReader("
49 // << " #threads= " << number_of_threads <<" )"<<std::endl;
52 for (int i=0; i<number_of_threads; i++)
54 ThreadedImageReader* t = new ThreadedImageReader(this);
55 mThreadedImageReaderList.push_back(t);
57 mNumberOfThreadedReadersRunning = 0;
59 mQueue.set(mComparator);
62 // no thread : alloc self reader
63 if (number_of_threads==0)
65 mReader = new ImageReader();
68 //=====================================================================
71 //=====================================================================
72 bool MultiThreadImageReader::Start()
75 // std::cout << "#### MultiThreadImageReader::Start()"
77 ThreadedImageReaderListType::iterator i;
78 for (i =mThreadedImageReaderList.begin();
79 i!=mThreadedImageReaderList.end();
83 if ( (*i)->Run() != wxTHREAD_NO_ERROR )
85 std::cout << "ERROR starting a thread"<< std::endl;
90 // std::cout << " ===> Thread "<<(*i)->GetCurrentId()
91 // <<" successfully created"<< std::endl;
95 wxMutexLocker locker(GetMultiThreadImageReaderUserMutex());
96 // std::cout << "EO Start : #Threads running = "
97 // << mNumberOfThreadedReadersRunning<<std::endl;
101 //=====================================================================
103 //=====================================================================
104 void MultiThreadImageReader::Stop()
106 // std::cout << "#### MultiThreadImageReader::Stop()"
108 // std::cout << "Sending stop order to the threads..."<<std::endl;
110 ThreadedImageReaderListType::iterator i;
111 for (i =mThreadedImageReaderList.begin();
112 i!=mThreadedImageReaderList.end();
117 mThreadedImageReaderList.clear();
118 // Wait a little to be sure that all threads have stopped
119 // A better way to do this ?
120 // wxMilliSleep(1000);
121 // New method : the threads generate a stop event when they have finished
122 // We wait until all threads have stopped
123 // std::cout << "Waiting for stop signals..."<<std::endl;
130 wxMutexLocker locker(GetMultiThreadImageReaderUserMutex());
131 // std::cout << "#Threads running = "
132 // << mNumberOfThreadedReadersRunning<<std::endl;
133 // Break if all readers have stopped
134 if (mNumberOfThreadedReadersRunning <= 0)
141 // std::cout << "All threads stopped : OK "<<std::endl;
143 ImageMapType::iterator j;
144 for (j =mImages.begin();
153 //=====================================================================
155 //=====================================================================
156 MultiThreadImageReader::~MultiThreadImageReader()
158 // std::cout << "#### MultiThreadImageReader::~MultiThreadImageReader()"
161 if (mReader) delete mReader;
163 //=====================================================================
165 //=====================================================================
166 void MultiThreadImageReader::UpdateUnloadPriority(ImageToLoadPtr p,
169 // not in unload queue : ciao
170 if (p->UnloadIndex()<0) return;
171 int old_prio = p->GetPriority();
172 if (priority > old_prio)
174 p->SetPriority(priority);
175 mUnloadQueue.downsort(p->UnloadIndex());
177 else if ( old_prio > priority )
179 p->SetPriority(priority);
180 mUnloadQueue.upsort(p->UnloadIndex());
183 //=====================================================================
185 //=====================================================================
186 void MultiThreadImageReader::Request( MultiThreadImageReaderUser* user,
187 const std::string& filename,
190 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
192 if (mThreadedImageReaderList.size()==0)
194 // no detached reader : use self reader
195 ImageToLoad itl(user,filename);
196 ImageMapType::iterator i = mImages.find(&itl);
197 if (i!=mImages.end())
199 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
201 if (pitl->GetImage() != 0)
205 UpdateUnloadPriority(pitl,priority);
206 SignalImageRead(pitl,false);
207 return; // pitl->GetImage();
210 ImageToLoadPtr pitl = new ImageToLoad(user,filename,0);
212 pitl->SetImage(mReader->ReadImage(filename));
213 UpdateUnloadPriority(pitl,priority);
214 SignalImageRead(pitl,true);
215 // return pitl->GetImage();
220 ImageToLoad itl(user,filename);
221 ImageMapType::iterator i = mImages.find(&itl);
222 if (i!=mImages.end())
225 if (i->first->GetImage() != 0)
227 // Already read : ok :signal the user
228 UpdateUnloadPriority(i->first,priority);
229 SignalImageRead(i->first,false);
232 /// Already requested : change the priority
233 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
234 pitl->SetPriority(priority);
236 if (pitl->Index()>=0)
239 mQueue.upsort(pitl->Index());
241 // Not read but not in queue = being read = ok
249 // Never requested before or unloaded
250 ImageToLoadPtr pitl = new ImageToLoad(user,filename,priority);
255 //=====================================================================
257 //=====================================================================
258 void MultiThreadImageReader::OnMultiThreadImageReaderEvent
259 (const std::string& filename,
260 MultiThreadImageReaderUser::EventType e,
263 if ((e==MultiThreadImageReaderUser::ImageLoaded) &&
264 (filename == mRequestedFilename))
266 mRequestedImage = image;
268 else if (e==MultiThreadImageReaderUser::ThreadedReaderStarted)
270 mNumberOfThreadedReadersRunning++;
271 // std::cout << "#TR=" << mNumberOfThreadedReadersRunning << std::endl;
273 else if (e==MultiThreadImageReaderUser::ThreadedReaderStopped)
275 mNumberOfThreadedReadersRunning--;
276 // std::cout << "#TR=" << mNumberOfThreadedReadersRunning << std::endl;
279 //=====================================================================
281 //=====================================================================
282 vtkImageData* MultiThreadImageReader::GetImage(const std::string& filename)
285 // std::cout << "** MultiThreadImageReader::GetImage('"<<filename<<"')"
290 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
292 if (mThreadedImageReaderList.size()==0)
294 ImageToLoad itl(this,filename);
295 ImageMapType::iterator i = mImages.find(&itl);
296 if (i!=mImages.end())
298 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
300 if (pitl->GetImage() != 0)
303 UpdateUnloadPriority(pitl,
304 GetMaximalPriorityWithoutLocking()+1);
305 return pitl->GetImage();
308 ImageToLoadPtr pitl = new ImageToLoad(this,filename,0);
310 pitl->SetImage(mReader->ReadImage(filename));
311 UpdateUnloadPriority(pitl,
312 GetMaximalPriorityWithoutLocking()+1);
313 return pitl->GetImage();
316 mRequestedFilename = filename;
318 ImageToLoad itl(this,filename);
319 ImageMapType::iterator i = mImages.find(&itl);
320 if (i!=mImages.end())
322 // Already inserted in queue
323 if (i->first->GetImage() != 0)
325 // Already read : ok : return it
326 return i->first->GetImage();
328 /// Already requested : change the priority
329 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
330 pitl->SetPriority( GetMaximalPriorityWithoutLocking() + 1 );
331 pitl->SetUser( this );
333 if (pitl->Index()>=0)
336 mQueue.upsort(pitl->Index());
338 // Not read but not in queue = being read = ok
341 pitl->SetUser( this );
347 // Never requested before or unloaded
348 ImageToLoadPtr pitl =
349 new ImageToLoad(this,filename,
350 GetMaximalPriorityWithoutLocking() + 1);
357 // std::cout << "Waiting..."<<std::endl;
359 // Waiting that it is read
363 // std::cout << n++ << std::endl;
367 // wxMutexLocker lock(mMutex);
368 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex());
369 if (mRequestedImage!=0)
371 return mRequestedImage;
380 //=====================================================================
382 //=====================================================================
383 void MultiThreadImageReader::SignalImageRead(ImageToLoadPtr p,
387 // std::cout << "MultiThreadImageReader::SignalImageRead" <<std::endl;
388 // std::cout << "this="<<this <<std::endl;
389 // std::cout << "user="<<p->GetUser() <<std::endl;
391 if ( p->GetUser() == this )
392 GetMultiThreadImageReaderUserMutex().Unlock();
394 p->GetUser()->MultiThreadImageReaderSendEvent
396 MultiThreadImageReaderUser::ImageLoaded,
400 AN ATTEMPT TO UNLOAD OLDEST IMAGE IF EXCEEDED A CERTAIN MEMORY QUOTA
404 GimmickMessage(5,"Image '"<<p->GetFilename()<<"' read"<<std::endl);
406 // wxMutexLocker lock(GetMultiThreadImageReaderUserMutex());
408 mUnloadQueue.insert(p);
409 p->GetImage()->UpdateInformation();
410 p->GetImage()->PropagateUpdateExtent();
411 long ImMem = p->GetImage()->GetEstimatedMemorySize();
414 GimmickMessage(5,"==> Image in memory = "<<mUnloadQueue.size()<<std::endl);
415 GimmickMessage(5,"==> Total mem = "<<mTotalMem<<" Ko"<<std::endl);
419 while (mTotalMem > mTotalMemMax)
422 " ! Exceeded max of "
423 << mTotalMemMax << " Ko : unloading oldest image ... "
425 if ( mUnloadQueue.size() <= 1 )
428 " Only one image : cannot load AND unload it !!"
433 ImageToLoadPtr unload = mUnloadQueue.remove_top();
434 MultiThreadImageReaderUser* user = unload->GetUser();
436 if ((user!=0)&&(user!=this))
438 user->GetMultiThreadImageReaderUserMutex().Lock();
442 GimmickMessage(5,"'" << unload->GetFilename() << "'" << std::endl);
443 mTotalMem -= unload->GetImage()->GetEstimatedMemorySize();
445 GimmickMessage(5," ==> Total mem = "<<mTotalMem<<" Ko "<<std::endl);
448 std::string filename = unload->GetFilename();
449 if (unload->Index()>=0)
451 // GimmickMessage(5,"still in queue"<<std::endl);
453 unload->Index() = -1;
456 ImageMapType::iterator it = mImages.find(unload);
457 if (it!=mImages.end())
461 // std::cout << "delete..."<<std::endl;
463 // std::cout << "delete ok."<<std::endl;
467 // std::cout << "unlock..."<<std::endl;
468 user->GetMultiThreadImageReaderUserMutex().Unlock();
469 // std::cout << "event"<<std::endl;
470 user->MultiThreadImageReaderSendEvent
472 MultiThreadImageReaderUser::ImageUnloaded,
474 // std::cout << "event ok"<<std::endl;
481 //=====================================================================
483 //=====================================================================
484 int MultiThreadImageReader::GetMaximalPriority()
486 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
487 return GetMaximalPriorityWithoutLocking();
489 //=====================================================================
492 //=====================================================================
493 int MultiThreadImageReader::GetMaximalPriorityWithoutLocking()
498 max = mQueue.top()->GetPriority();
500 if (mUnloadQueue.size()>0)
502 int max2 = mUnloadQueue.top()->GetPriority();
503 if (max2>max) max=max2;
507 //=====================================================================
510 //=====================================================================
511 //=====================================================================
512 //=====================================================================
513 //=====================================================================
515 //=====================================================================
516 void* ThreadedImageReader::Entry()
518 // std::cout << "### Thread "<<GetCurrentId()<<"::Entry()"
521 mMultiThreadImageReader->MultiThreadImageReaderSendEvent
523 MultiThreadImageReaderUser::ThreadedReaderStarted,
526 // While was not deleted
527 while (!TestDestroy())
529 // std::cout << "### Thread "<<GetCurrentId()<<" waiting for image"
533 mMultiThreadImageReader->MultiThreadImageReaderEventLock();
536 if (mMultiThreadImageReader->mQueue.size()>0)
538 MultiThreadImageReader::ImageToLoadPtr i =
539 mMultiThreadImageReader->mQueue.remove_top();
541 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();
545 // std::cout << "### Thread "<<GetCurrentId()<<" : reading '"
546 // << i->GetFilename() << "'" << std::endl;
549 vtkImageData* im = Read(i->GetFilename());
551 // Store it in the map
552 mMultiThreadImageReader->MultiThreadImageReaderEventLock();
554 MultiThreadImageReader::ImageToLoad itl(0,i->GetFilename());
555 MultiThreadImageReader::ImageMapType::iterator it =
556 mMultiThreadImageReader->mImages.find(&itl);
557 MultiThreadImageReader::ImageToLoadPtr
558 pitl = const_cast<MultiThreadImageReader::ImageToLoadPtr>
561 mMultiThreadImageReader->SignalImageRead(pitl,true);//i->GetFilename());
562 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock(); //mMutex.Unlock();
564 // std::cout << "### Thread "<<GetCurrentId()<<" : reading '"
565 // << i->GetFilename() << "' : DONE" << std::endl;
570 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();
572 // Wait a little to avoid blocking
576 // std::cout << "### Thread "<<GetCurrentId()<<" stopping"
581 //=====================================================================
583 //=====================================================================
584 void ThreadedImageReader::OnExit()
586 mMultiThreadImageReader->MultiThreadImageReaderSendEvent
588 MultiThreadImageReaderUser::ThreadedReaderStopped,
591 //=====================================================================
593 //=====================================================================
594 vtkImageData* ThreadedImageReader::Read(const std::string& filename)
596 return mReader.ReadImage(filename);
598 //=====================================================================
600 } // namespace creaImageIO