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 if (mNumberOfThreadedReadersRunning > 0) return true;
79 ThreadedImageReaderListType::iterator i;
80 for (i =mThreadedImageReaderList.begin();
81 i!=mThreadedImageReaderList.end();
85 if ( (*i)->Run() != wxTHREAD_NO_ERROR )
87 std::cout << "ERROR starting a thread"<< std::endl;
92 // std::cout << " ===> Thread "<<(*i)->GetCurrentId()
93 // <<" successfully created"<< std::endl;
97 wxMutexLocker locker(GetMultiThreadImageReaderUserMutex());
98 // std::cout << "EO Start : #Threads running = "
99 // << mNumberOfThreadedReadersRunning<<std::endl;
103 //=====================================================================
105 //=====================================================================
106 void MultiThreadImageReader::Stop()
108 // std::cout << "#### MultiThreadImageReader::Stop()"
110 // std::cout << "Sending stop order to the threads..."<<std::endl;
112 ThreadedImageReaderListType::iterator i;
113 for (i =mThreadedImageReaderList.begin();
114 i!=mThreadedImageReaderList.end();
119 mThreadedImageReaderList.clear();
120 // Wait a little to be sure that all threads have stopped
121 // A better way to do this ?
122 // wxMilliSleep(1000);
123 // New method : the threads generate a stop event when they have finished
124 // We wait until all threads have stopped
125 // std::cout << "Waiting for stop signals..."<<std::endl;
132 wxMutexLocker locker(GetMultiThreadImageReaderUserMutex());
133 // std::cout << "#Threads running = "
134 // << mNumberOfThreadedReadersRunning<<std::endl;
135 // Break if all readers have stopped
136 if (mNumberOfThreadedReadersRunning <= 0)
143 // std::cout << "All threads stopped : OK "<<std::endl;
145 ImageMapType::iterator j;
146 for (j =mImages.begin();
155 //=====================================================================
157 //=====================================================================
158 MultiThreadImageReader::~MultiThreadImageReader()
160 // std::cout << "#### MultiThreadImageReader::~MultiThreadImageReader()"
163 if (mReader) delete mReader;
165 //=====================================================================
167 //=====================================================================
168 void MultiThreadImageReader::UpdateUnloadPriority(ImageToLoadPtr p,
171 // not in unload queue : ciao
172 if (p->UnloadIndex()<0) return;
173 int old_prio = p->GetPriority();
174 if (priority > old_prio)
176 p->SetPriority(priority);
177 mUnloadQueue.downsort(p->UnloadIndex());
179 else if ( old_prio > priority )
181 p->SetPriority(priority);
182 mUnloadQueue.upsort(p->UnloadIndex());
185 //=====================================================================
187 //=====================================================================
188 void MultiThreadImageReader::Request( MultiThreadImageReaderUser* user,
189 const std::string& filename,
192 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
194 if (mNumberOfThreadedReadersRunning==0)
195 // if (mThreadedImageReaderList.size()==0)
197 // no detached reader : use self reader
198 ImageToLoad itl(user,filename);
199 ImageMapType::iterator i = mImages.find(&itl);
200 if (i!=mImages.end())
202 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
204 if (pitl->GetImage() != 0)
208 UpdateUnloadPriority(pitl,priority);
209 SignalImageRead(pitl,false);
210 return; // pitl->GetImage();
213 ImageToLoadPtr pitl = new ImageToLoad(user,filename,0);
215 pitl->SetImage(mReader->ReadImage(filename));
216 UpdateUnloadPriority(pitl,priority);
217 SignalImageRead(pitl,true);
218 // return pitl->GetImage();
223 ImageToLoad itl(user,filename);
224 ImageMapType::iterator i = mImages.find(&itl);
225 if (i!=mImages.end())
228 if (i->first->GetImage() != 0)
230 // Already read : ok :signal the user
231 UpdateUnloadPriority(i->first,priority);
232 SignalImageRead(i->first,false);
235 /// Already requested : change the priority
236 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
237 pitl->SetPriority(priority);
239 if (pitl->Index()>=0)
242 mQueue.upsort(pitl->Index());
244 // Not read but not in queue = being read = ok
252 // Never requested before or unloaded
253 ImageToLoadPtr pitl = new ImageToLoad(user,filename,priority);
258 //=====================================================================
260 //=====================================================================
261 void MultiThreadImageReader::OnMultiThreadImageReaderEvent
262 (const std::string& filename,
263 MultiThreadImageReaderUser::EventType e,
266 if ((e==MultiThreadImageReaderUser::ImageLoaded) &&
267 (filename == mRequestedFilename))
269 mRequestedImage = image;
271 else if (e==MultiThreadImageReaderUser::ThreadedReaderStarted)
273 mNumberOfThreadedReadersRunning++;
274 // std::cout << "#TR=" << mNumberOfThreadedReadersRunning << std::endl;
276 else if (e==MultiThreadImageReaderUser::ThreadedReaderStopped)
278 mNumberOfThreadedReadersRunning--;
279 // std::cout << "#TR=" << mNumberOfThreadedReadersRunning << std::endl;
282 //=====================================================================
284 //=====================================================================
285 vtkImageData* MultiThreadImageReader::GetImage(const std::string& filename)
288 // std::cout << "** MultiThreadImageReader::GetImage('"<<filename<<"')"
293 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
295 if (mNumberOfThreadedReadersRunning==0)
296 // if (mThreadedImageReaderList.size()==0)
298 ImageToLoad itl(this,filename);
299 ImageMapType::iterator i = mImages.find(&itl);
300 if (i!=mImages.end())
302 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
304 if (pitl->GetImage() != 0)
307 UpdateUnloadPriority(pitl,
308 GetMaximalPriorityWithoutLocking()+1);
309 return pitl->GetImage();
312 ImageToLoadPtr pitl = new ImageToLoad(this,filename,0);
314 pitl->SetImage(mReader->ReadImage(filename));
315 UpdateUnloadPriority(pitl,
316 GetMaximalPriorityWithoutLocking()+1);
317 return pitl->GetImage();
320 mRequestedFilename = filename;
322 ImageToLoad itl(this,filename);
323 ImageMapType::iterator i = mImages.find(&itl);
324 if (i!=mImages.end())
326 // Already inserted in queue
327 if (i->first->GetImage() != 0)
329 // Already read : ok : return it
330 return i->first->GetImage();
332 /// Already requested : change the priority
333 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
334 pitl->SetPriority( GetMaximalPriorityWithoutLocking() + 1 );
335 pitl->SetUser( this );
337 if (pitl->Index()>=0)
340 mQueue.upsort(pitl->Index());
342 // Not read but not in queue = being read = ok
345 pitl->SetUser( this );
351 // Never requested before or unloaded
352 ImageToLoadPtr pitl =
353 new ImageToLoad(this,filename,
354 GetMaximalPriorityWithoutLocking() + 1);
361 // std::cout << "Waiting..."<<std::endl;
363 // Waiting that it is read
367 // std::cout << n++ << std::endl;
371 // wxMutexLocker lock(mMutex);
372 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex());
373 if (mRequestedImage!=0)
375 return mRequestedImage;
384 //=====================================================================
386 //=====================================================================
387 void MultiThreadImageReader::SignalImageRead(ImageToLoadPtr p,
391 // std::cout << "MultiThreadImageReader::SignalImageRead" <<std::endl;
392 // std::cout << "this="<<this <<std::endl;
393 // std::cout << "user="<<p->GetUser() <<std::endl;
395 if ( p->GetUser() == this )
396 GetMultiThreadImageReaderUserMutex().Unlock();
398 p->GetUser()->MultiThreadImageReaderSendEvent
400 MultiThreadImageReaderUser::ImageLoaded,
404 AN ATTEMPT TO UNLOAD OLDEST IMAGE IF EXCEEDED A CERTAIN MEMORY QUOTA
408 GimmickMessage(5,"Image '"<<p->GetFilename()<<"' read"<<std::endl);
410 // wxMutexLocker lock(GetMultiThreadImageReaderUserMutex());
412 mUnloadQueue.insert(p);
413 p->GetImage()->UpdateInformation();
414 p->GetImage()->PropagateUpdateExtent();
415 long ImMem = p->GetImage()->GetEstimatedMemorySize();
418 GimmickMessage(5,"==> Image in memory = "<<mUnloadQueue.size()<<std::endl);
419 GimmickMessage(5,"==> Total mem = "<<mTotalMem<<" Ko"<<std::endl);
423 while (mTotalMem > mTotalMemMax)
426 " ! Exceeded max of "
427 << mTotalMemMax << " Ko : unloading oldest image ... "
429 if ( mUnloadQueue.size() <= 1 )
432 " Only one image : cannot load AND unload it !!"
437 ImageToLoadPtr unload = mUnloadQueue.remove_top();
438 MultiThreadImageReaderUser* user = unload->GetUser();
440 if ((user!=0)&&(user!=this))
442 user->GetMultiThreadImageReaderUserMutex().Lock();
446 GimmickMessage(5,"'" << unload->GetFilename() << "'" << std::endl);
447 mTotalMem -= unload->GetImage()->GetEstimatedMemorySize();
449 GimmickMessage(5," ==> Total mem = "<<mTotalMem<<" Ko "<<std::endl);
452 std::string filename = unload->GetFilename();
453 if (unload->Index()>=0)
455 // GimmickMessage(5,"still in queue"<<std::endl);
457 unload->Index() = -1;
460 ImageMapType::iterator it = mImages.find(unload);
461 if (it!=mImages.end())
465 // std::cout << "delete..."<<std::endl;
467 // std::cout << "delete ok."<<std::endl;
471 // std::cout << "unlock..."<<std::endl;
472 user->GetMultiThreadImageReaderUserMutex().Unlock();
473 // std::cout << "event"<<std::endl;
474 user->MultiThreadImageReaderSendEvent
476 MultiThreadImageReaderUser::ImageUnloaded,
478 // std::cout << "event ok"<<std::endl;
485 //=====================================================================
487 //=====================================================================
488 int MultiThreadImageReader::GetMaximalPriority()
490 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
491 return GetMaximalPriorityWithoutLocking();
493 //=====================================================================
496 //=====================================================================
497 int MultiThreadImageReader::GetMaximalPriorityWithoutLocking()
502 max = mQueue.top()->GetPriority();
504 if (mUnloadQueue.size()>0)
506 int max2 = mUnloadQueue.top()->GetPriority();
507 if (max2>max) max=max2;
511 //=====================================================================
514 //=====================================================================
515 //=====================================================================
516 //=====================================================================
517 //=====================================================================
519 //=====================================================================
520 void* ThreadedImageReader::Entry()
522 // std::cout << "### Thread "<<GetCurrentId()<<"::Entry()"
525 mMultiThreadImageReader->MultiThreadImageReaderSendEvent
527 MultiThreadImageReaderUser::ThreadedReaderStarted,
530 // While was not deleted
531 while (!TestDestroy())
533 // std::cout << "### Thread "<<GetCurrentId()<<" waiting for image"
537 mMultiThreadImageReader->MultiThreadImageReaderEventLock();
540 if (mMultiThreadImageReader->mQueue.size()>0)
542 MultiThreadImageReader::ImageToLoadPtr i =
543 mMultiThreadImageReader->mQueue.remove_top();
545 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();
549 // std::cout << "### Thread "<<GetCurrentId()<<" : reading '"
550 // << i->GetFilename() << "'" << std::endl;
553 vtkImageData* im = Read(i->GetFilename());
555 // Store it in the map
556 mMultiThreadImageReader->MultiThreadImageReaderEventLock();
558 MultiThreadImageReader::ImageToLoad itl(0,i->GetFilename());
559 MultiThreadImageReader::ImageMapType::iterator it =
560 mMultiThreadImageReader->mImages.find(&itl);
561 MultiThreadImageReader::ImageToLoadPtr
562 pitl = const_cast<MultiThreadImageReader::ImageToLoadPtr>
565 mMultiThreadImageReader->SignalImageRead(pitl,true);//i->GetFilename());
566 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock(); //mMutex.Unlock();
568 // std::cout << "### Thread "<<GetCurrentId()<<" : reading '"
569 // << i->GetFilename() << "' : DONE" << std::endl;
574 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();
576 // Wait a little to avoid blocking
580 // std::cout << "### Thread "<<GetCurrentId()<<" stopping"
585 //=====================================================================
587 //=====================================================================
588 void ThreadedImageReader::OnExit()
590 mMultiThreadImageReader->MultiThreadImageReaderSendEvent
592 MultiThreadImageReaderUser::ThreadedReaderStopped,
595 //=====================================================================
597 //=====================================================================
598 vtkImageData* ThreadedImageReader::Read(const std::string& filename)
600 return mReader.ReadImage(filename);
602 //=====================================================================
604 } // namespace creaImageIO