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 mThreadedImageReaderList.push_back(t);
58 std::cout << " ===> Thread "<<i
59 <<" successfully added"<< std::endl;
61 mNumberOfThreadedReadersRunning = 0;
63 mQueue.set(mComparator);
66 // no thread : alloc self reader
67 // if (number_of_threads==0)
69 mReader = new ImageReader();
72 //=====================================================================
75 //=====================================================================
76 bool MultiThreadImageReader::Start()
79 // std::cout << "#### MultiThreadImageReader::Start()"
81 if (mNumberOfThreadedReadersRunning > 0) return true;
83 ThreadedImageReaderListType::iterator i;
84 for (i =mThreadedImageReaderList.begin();
85 i!=mThreadedImageReaderList.end();
89 if ( (*i)->Run() != wxTHREAD_NO_ERROR )
91 std::cout << "ERROR starting a thread"<< std::endl;
96 std::cout << " ===> Thread "<<(*i)->GetCurrentId()
97 <<" successfully created"<< std::endl;
101 wxMutexLocker locker(GetMultiThreadImageReaderUserMutex());
102 // std::cout << "EO Start : #Threads running = "
103 // << mNumberOfThreadedReadersRunning<<std::endl;
107 //=====================================================================
109 //=====================================================================
110 void MultiThreadImageReader::Stop()
112 // std::cout << "#### MultiThreadImageReader::Stop()"
114 // std::cout << "Sending stop order to the threads..."<<std::endl;
116 ThreadedImageReaderListType::iterator i;
117 for (i =mThreadedImageReaderList.begin();
118 i!=mThreadedImageReaderList.end();
120 { std::cout << " ===> Thread "<<(*i)->GetCurrentId()
121 <<" successfully stopped"<< std::endl;
127 mThreadedImageReaderList.clear();
128 // Wait a little to be sure that all threads have stopped
129 // A better way to do this ?
130 // wxMilliSleep(1000);
131 // New method : the threads generate a stop event when they have finished
132 // We wait until all threads have stopped
133 // std::cout << "Waiting for stop signals..."<<std::endl;
140 wxMutexLocker locker(GetMultiThreadImageReaderUserMutex());
141 // std::cout << "#Threads running = "
142 // << mNumberOfThreadedReadersRunning<<std::endl;
143 // Break if all readers have stopped
144 if (mNumberOfThreadedReadersRunning <= 0)
151 // std::cout << "All threads stopped : OK "<<std::endl;
153 ImageMapType::iterator j;
154 for (j =mImages.begin();
163 //=====================================================================
165 //=====================================================================
166 MultiThreadImageReader::~MultiThreadImageReader()
168 // std::cout << "#### MultiThreadImageReader::~MultiThreadImageReader()"
171 if (mReader) delete mReader;
173 //=====================================================================
175 //=====================================================================
176 void MultiThreadImageReader::UpdateUnloadPriority(ImageToLoadPtr p,
179 // not in unload queue : ciao
180 if (p->UnloadIndex()<0) return;
181 int old_prio = p->GetPriority();
182 if (priority > old_prio)
184 p->SetPriority(priority);
185 mUnloadQueue.downsort(p->UnloadIndex());
187 else if ( old_prio > priority )
189 p->SetPriority(priority);
190 mUnloadQueue.upsort(p->UnloadIndex());
193 //=====================================================================
195 //=====================================================================
196 void MultiThreadImageReader::Request( MultiThreadImageReaderUser* user,
197 const std::string& filename,
200 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
202 if (mNumberOfThreadedReadersRunning==0)
203 // if (mThreadedImageReaderList.size()==0)
205 // no detached reader : use self reader
206 ImageToLoad itl(user,filename);
207 ImageMapType::iterator i = mImages.find(&itl);
208 if (i!=mImages.end())
210 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
212 if (pitl->GetImage() != 0)
216 UpdateUnloadPriority(pitl,priority);
217 SignalImageRead(pitl,false);
218 return; // pitl->GetImage();
221 ImageToLoadPtr pitl = new ImageToLoad(user,filename,0);
223 pitl->SetImage(mReader->ReadImage(filename));
224 UpdateUnloadPriority(pitl,priority);
225 SignalImageRead(pitl,true);
226 // return pitl->GetImage();
231 ImageToLoad itl(user,filename);
232 ImageMapType::iterator i = mImages.find(&itl);
233 if (i!=mImages.end())
236 if (i->first->GetImage() != 0)
238 // Already read : ok :signal the user
239 UpdateUnloadPriority(i->first,priority);
240 SignalImageRead(i->first,false);
243 /// Already requested : change the priority
244 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
245 pitl->SetPriority(priority);
247 if (pitl->Index()>=0)
250 mQueue.upsort(pitl->Index());
252 // Not read but not in queue = being read = ok
260 // Never requested before or unloaded
261 ImageToLoadPtr pitl = new ImageToLoad(user,filename,priority);
266 //=====================================================================
268 //=====================================================================
269 void MultiThreadImageReader::OnMultiThreadImageReaderEvent
270 (const std::string& filename,
271 MultiThreadImageReaderUser::EventType e,
274 if ((e==MultiThreadImageReaderUser::ImageLoaded) &&
275 (filename == mRequestedFilename))
277 mRequestedImage = image;
279 else if (e==MultiThreadImageReaderUser::ThreadedReaderStarted)
281 mNumberOfThreadedReadersRunning++;
282 // std::cout << "#TR=" << mNumberOfThreadedReadersRunning << std::endl;
284 else if (e==MultiThreadImageReaderUser::ThreadedReaderStopped)
287 mNumberOfThreadedReadersRunning--;
288 // std::cout << "#TR=" << mNumberOfThreadedReadersRunning << std::endl;
291 //=====================================================================
293 //=====================================================================
294 vtkImageData* MultiThreadImageReader::GetImage(const std::string& filename)
297 // std::cout << "** MultiThreadImageReader::GetImage('"<<filename<<"')"
302 // wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
304 // std::cout << "** MultiThreadImageReader::GetImage('"<<filename
308 // if (mNumberOfThreadedReadersRunning==0)
309 // if (mThreadedImageReaderList.size()==0)
312 ImageToLoad itl(this,filename);
313 ImageMapType::iterator i = mImages.find(&itl);
314 if (i!=mImages.end())
316 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
318 if (pitl->GetImage() != 0)
321 UpdateUnloadPriority(pitl,
322 GetMaximalPriorityWithoutLocking()+1);
323 return pitl->GetImage();
326 ImageToLoadPtr pitl = new ImageToLoad(this,filename,0);
328 pitl->SetImage(mReader->ReadImage(filename));
329 UpdateUnloadPriority(pitl,
330 GetMaximalPriorityWithoutLocking()+1);
331 return pitl->GetImage();
335 mRequestedFilename = filename;
337 ImageToLoad itl(this,filename);
338 ImageMapType::iterator i = mImages.find(&itl);
339 if (i!=mImages.end())
341 // Already inserted in queue
342 if (i->first->GetImage() != 0)
344 // Already read : ok : return it
345 return i->first->GetImage();
347 /// Already requested : change the priority
348 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
349 pitl->SetPriority( GetMaximalPriorityWithoutLocking() + 1 );
350 pitl->SetUser( this );
352 if (pitl->Index()>=0)
355 mQueue.upsort(pitl->Index());
357 // Not read but not in queue = being read = ok
360 pitl->SetUser( this );
366 // Never requested before or unloaded
367 ImageToLoadPtr pitl =
368 new ImageToLoad(this,filename,
369 GetMaximalPriorityWithoutLocking() + 1);
377 // std::cout << "Waiting..."<<std::endl;
380 // Waiting that it is read
384 // std::cout << n++ << std::endl;
388 // wxMutexLocker lock(mMutex);
389 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex());
390 if (mRequestedImage!=0)
392 return mRequestedImage;
401 //=====================================================================
403 //=====================================================================
404 void MultiThreadImageReader::SignalImageRead(ImageToLoadPtr p,
408 // std::cout << "MultiThreadImageReader::SignalImageRead" <<std::endl;
409 // std::cout << "this="<<this <<std::endl;
410 // std::cout << "user="<<p->GetUser() <<std::endl;
412 if ( p->GetUser() == this )
413 GetMultiThreadImageReaderUserMutex().Unlock();
415 p->GetUser()->MultiThreadImageReaderSendEvent
417 MultiThreadImageReaderUser::ImageLoaded,
421 AN ATTEMPT TO UNLOAD OLDEST IMAGE IF EXCEEDED A CERTAIN MEMORY QUOTA
425 GimmickMessage(5,"Image '"<<p->GetFilename()<<"' read"<<std::endl);
427 // wxMutexLocker lock(GetMultiThreadImageReaderUserMutex());
429 mUnloadQueue.insert(p);
430 p->GetImage()->UpdateInformation();
431 p->GetImage()->PropagateUpdateExtent();
432 long ImMem = p->GetImage()->GetEstimatedMemorySize();
435 GimmickMessage(5,"==> Image in memory = "<<mUnloadQueue.size()<<std::endl);
436 GimmickMessage(5,"==> Total mem = "<<mTotalMem<<" Ko"<<std::endl);
440 while (mTotalMem > mTotalMemMax)
443 " ! Exceeded max of "
444 << mTotalMemMax << " Ko : unloading oldest image ... "
446 if ( mUnloadQueue.size() <= 1 )
449 " Only one image : cannot load AND unload it !!"
454 ImageToLoadPtr unload = mUnloadQueue.remove_top();
455 MultiThreadImageReaderUser* user = unload->GetUser();
458 if ((user!=0)&&(user!=this))
460 user->GetMultiThreadImageReaderUserMutex().Lock();
464 std::string filename = unload->GetFilename();
466 GimmickMessage(5,"'" << filename << "'" << std::endl);
467 mTotalMem -= unload->GetImage()->GetEstimatedMemorySize();
469 GimmickMessage(5," ==> Total mem = "<<mTotalMem<<" Ko "<<std::endl);
474 // std::cout << "unlock..."<<std::endl;
475 // user->GetMultiThreadImageReaderUserMutex().Unlock();
476 // std::cout << "event"<<std::endl;
477 user->MultiThreadImageReaderSendEvent
479 MultiThreadImageReaderUser::ImageUnloaded,
481 // std::cout << "event ok"<<std::endl;
485 if (unload->Index()>=0)
487 // GimmickMessage(5,"still in queue"<<std::endl);
489 unload->Index() = -1;
492 ImageMapType::iterator it = mImages.find(unload);
493 if (it!=mImages.end())
497 // std::cout << "delete..."<<std::endl;
499 // std::cout << "delete ok."<<std::endl;
505 //=====================================================================
507 //=====================================================================
508 int MultiThreadImageReader::GetMaximalPriority()
510 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
511 return GetMaximalPriorityWithoutLocking();
513 //=====================================================================
516 //=====================================================================
517 int MultiThreadImageReader::GetMaximalPriorityWithoutLocking()
522 max = mQueue.top()->GetPriority();
524 if (mUnloadQueue.size()>0)
526 int max2 = mUnloadQueue.top()->GetPriority();
527 if (max2>max) max=max2;
531 //=====================================================================
534 //=====================================================================
535 //=====================================================================
536 //=====================================================================
537 //=====================================================================
539 //=====================================================================
540 void* ThreadedImageReader::Entry()
542 // std::cout << "### Thread "<<GetCurrentId()<<"::Entry()"
545 mMultiThreadImageReader->MultiThreadImageReaderSendEvent
547 MultiThreadImageReaderUser::ThreadedReaderStarted,
550 // While was not deleted
551 while (!TestDestroy())
553 //std::cout << "### Thread "<<GetCurrentId()<<" still alive" << std::endl;
556 mMultiThreadImageReader->MultiThreadImageReaderEventLock();
559 if (mMultiThreadImageReader->mQueue.size()>0)
561 MultiThreadImageReader::ImageToLoadPtr i =
562 mMultiThreadImageReader->mQueue.remove_top();
564 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();
568 // std::cout << "### Thread "<<GetCurrentId()<<" : reading '"
569 // << i->GetFilename() << "'" << std::endl;
572 vtkImageData* im = Read(i->GetFilename());
574 // Store it in the map
575 mMultiThreadImageReader->MultiThreadImageReaderEventLock();
577 MultiThreadImageReader::ImageToLoad itl(0,i->GetFilename());
578 MultiThreadImageReader::ImageMapType::iterator it =
579 mMultiThreadImageReader->mImages.find(&itl);
580 MultiThreadImageReader::ImageToLoadPtr
581 pitl = const_cast<MultiThreadImageReader::ImageToLoadPtr>
584 mMultiThreadImageReader->SignalImageRead(pitl,true);//i->GetFilename());
585 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock(); //mMutex.Unlock();
587 // std::cout << "### Thread "<<GetCurrentId()<<" : reading '"
588 // << i->GetFilename() << "' : DONE" << std::endl;
593 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();
595 // Wait a little to avoid blocking
599 // std::cout << "### Thread "<<GetCurrentId()<<" stopping"
604 //=====================================================================
606 //=====================================================================
607 void ThreadedImageReader::OnExit()
609 mMultiThreadImageReader->MultiThreadImageReaderSendEvent
611 MultiThreadImageReaderUser::ThreadedReaderStopped,
614 //=====================================================================
616 //=====================================================================
617 vtkImageData* ThreadedImageReader::Read(const std::string& filename)
619 return mReader.ReadImage(filename);
621 //=====================================================================
623 } // namespace creaImageIO