1 #include <creaImageIOQMultiThreadImageReader.h>
2 #include <creaImageIOImageReader.h>
3 //#include <wx/utils.h>
5 #include <creaImageIOSystem.h>
7 #include <creaImageIOGimmick.h>
14 //=====================================================================
15 void MultiThreadImageReaderUser::MultiThreadImageReaderSendEvent
16 ( const std::string& filename,
20 QMutexLocker lock(&mMultiThreadImageReaderUserMutex);
22 this->OnMultiThreadImageReaderEvent(filename,type,image);
24 //=====================================================================
26 //=====================================================================
27 class ThreadedImageReader: public QThread
30 ThreadedImageReader(MultiThreadImageReader* tir) :
31 mMultiThreadImageReader(tir)
37 vtkImageData* Read(const std::string& filename);
41 void operator()(ThreadedImageReader* p)
46 friend struct deleter;
51 MultiThreadImageReader* mMultiThreadImageReader;
55 //=====================================================================
58 //=====================================================================
59 MultiThreadImageReader::MultiThreadImageReader(int number_of_threads)
60 : //mDoNotSignal(false),
65 // std::cout << "#### MultiThreadImageReader::MultiThreadImageReader("
66 // << " #threads= " << number_of_threads <<" )"<<std::endl;
70 for (int i=0; i<number_of_threads; i++)
72 //ThreadedImageReader* t = new ThreadedImageReader(this);
73 boost::shared_ptr<ThreadedImageReader> t(new ThreadedImageReader(this), ThreadedImageReader::deleter());
74 mThreadedImageReaderList.push_back(t);
75 std::cout << " ===> Thread "<<i
76 <<" successfully added"<< std::endl;
78 mNumberOfThreadedReadersRunning = 0;
80 mQueue.set(mComparator);
83 // no thread : alloc self reader
84 // if (number_of_threads==0)
86 mReader = new ImageReader();
89 //=====================================================================
92 //=====================================================================
93 bool MultiThreadImageReader::Start()
96 // std::cout << "#### MultiThreadImageReader::Start()"
98 if (mNumberOfThreadedReadersRunning > 0) return true;
100 ThreadedImageReaderListType::iterator i;
101 for (i =mThreadedImageReaderList.begin();
102 i!=mThreadedImageReaderList.end();
106 if ( !(*i)->isRunning() )
108 std::cout << "ERROR starting a thread"<< std::endl;
113 std::cout << " ===> Thread "<<(*i)->currentThreadId()
114 <<" successfully created"<< std::endl;
118 QMutexLocker locker(GetMultiThreadImageReaderUserMutex());
119 // std::cout << "EO Start : #Threads running = "
120 // << mNumberOfThreadedReadersRunning<<std::endl;
124 //=====================================================================
126 //=====================================================================
127 void MultiThreadImageReader::Stop()
129 // std::cout << "#### MultiThreadImageReader::Stop()"
131 // std::cout << "Sending stop order to the threads..."<<std::endl;
134 ThreadedImageReaderListType::iterator i;
135 for (i =mThreadedImageReaderList.begin();
136 i!=mThreadedImageReaderList.end();
138 { std::cout << " ===> Thread "<<(*i)->currentThreadId()
139 <<" successfully stopped"<< std::endl;
140 if(!(*i)->isFinished())
146 mThreadedImageReaderList.clear();
147 // Wait a little to be sure that all threads have stopped
148 // A better way to do this ?
149 // wxMilliSleep(1000);
150 // New method : the threads generate a stop event when they have finished
151 // We wait until all threads have stopped
152 // std::cout << "Waiting for stop signals..."<<std::endl;
156 // QThread::msleep(10);
159 QMutexLocker locker(GetMultiThreadImageReaderUserMutex());
160 // std::cout << "#Threads running = "
161 // << mNumberOfThreadedReadersRunning<<std::endl;
162 // Break if all readers have stopped
163 if (mNumberOfThreadedReadersRunning <= 0)
170 // std::cout << "All threads stopped : OK "<<std::endl;
172 ImageMapType::iterator j;
173 for (j =mImages.begin();
183 //=====================================================================
185 //=====================================================================
186 MultiThreadImageReader::~MultiThreadImageReader()
188 // std::cout << "#### MultiThreadImageReader::~MultiThreadImageReader()"
191 if (mReader) delete mReader;
192 mThreadedImageReaderList.clear();
194 //=====================================================================
196 //=====================================================================
197 void MultiThreadImageReader::UpdateUnloadPriority(ImageToLoadPtr p,
200 // not in unload queue : ciao
201 if (p->UnloadIndex()<0) return;
202 int old_prio = p->GetPriority();
203 if (priority > old_prio)
205 p->SetPriority(priority);
206 mUnloadQueue.downsort(p->UnloadIndex());
208 else if ( old_prio > priority )
210 p->SetPriority(priority);
211 mUnloadQueue.upsort(p->UnloadIndex());
214 //=====================================================================
215 // function to read attributes for a file
216 void MultiThreadImageReader::getAttributes(const std::string filename,
217 std::map <std::string , std::string> &infos,std::vector<std::string> i_attr)
219 mReader->getAttributes(filename, infos, i_attr);
222 //=====================================================================
223 void MultiThreadImageReader::Request( MultiThreadImageReaderUser* user,
224 const std::string& filename,
227 QMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
229 if (mNumberOfThreadedReadersRunning==0)
230 // if (mThreadedImageReaderList.size()==0)
232 // no detached reader : use self reader
233 ImageToLoad itl(user,filename);
234 ImageMapType::iterator i = mImages.find(&itl);
235 if (i!=mImages.end())
237 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
239 if (pitl->GetImage() != 0)
243 UpdateUnloadPriority(pitl,priority);
244 SignalImageRead(pitl,false);
245 return; // pitl->GetImage();
248 ImageToLoadPtr pitl = new ImageToLoad(user,filename,0);
250 pitl->SetImage(mReader->ReadImage(filename));
251 UpdateUnloadPriority(pitl,priority);
252 SignalImageRead(pitl,true);
253 // return pitl->GetImage();
257 ImageToLoad itl(user,filename);
258 ImageMapType::iterator i = mImages.find(&itl);
259 if (i!=mImages.end())
262 if (i->first->GetImage() != 0)
264 // Already read : ok :signal the user
265 UpdateUnloadPriority(i->first,priority);
266 SignalImageRead(i->first,false);
269 /// Already requested : change the priority
270 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
271 pitl->SetPriority(priority);
273 if (pitl->Index()>=0)
276 mQueue.upsort(pitl->Index());
278 // Not read but not in queue = being read = ok
286 // Never requested before or unloaded
287 ImageToLoadPtr pitl = new ImageToLoad(user,filename,priority);
292 //=====================================================================
294 //=====================================================================
295 void MultiThreadImageReader::OnMultiThreadImageReaderEvent
296 (const std::string& filename,
297 MultiThreadImageReaderUser::EventType e,
300 if ((e==MultiThreadImageReaderUser::ImageLoaded) &&
301 (filename == mRequestedFilename))
303 mRequestedImage = image;
305 else if (e==MultiThreadImageReaderUser::ThreadedReaderStarted)
307 mNumberOfThreadedReadersRunning++;
308 // std::cout << "#TR=" << mNumberOfThreadedReadersRunning << std::endl;
310 else if (e==MultiThreadImageReaderUser::ThreadedReaderStopped)
313 mNumberOfThreadedReadersRunning--;
314 // std::cout << "#TR=" << mNumberOfThreadedReadersRunning << std::endl;
317 //=====================================================================
319 //=====================================================================
320 vtkImageData* MultiThreadImageReader::GetImage(const std::string& filename)
323 // std::cout << "** MultiThreadImageReader::GetImage('"<<filename<<"')"
328 // wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
330 // std::cout << "** MultiThreadImageReader::GetImage('"<<filename
334 // if (mNumberOfThreadedReadersRunning==0)
335 // if (mThreadedImageReaderList.size()==0)
338 ImageToLoad itl(this,filename);
339 ImageMapType::iterator i = mImages.find(&itl);
340 if (i!=mImages.end())
342 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
344 if (pitl->GetImage() != 0)
347 UpdateUnloadPriority(pitl,
348 GetMaximalPriorityWithoutLocking()+1);
349 return pitl->GetImage();
352 ImageToLoadPtr pitl = new ImageToLoad(this,filename,0);
354 pitl->SetImage(mReader->ReadImage(filename));
355 UpdateUnloadPriority(pitl,
356 GetMaximalPriorityWithoutLocking()+1);
357 return pitl->GetImage();
361 mRequestedFilename = filename;
363 ImageToLoad itl(this,filename);
364 ImageMapType::iterator i = mImages.find(&itl);
365 if (i!=mImages.end())
367 // Already inserted in queue
368 if (i->first->GetImage() != 0)
370 // Already read : ok : return it
371 return i->first->GetImage();
373 /// Already requested : change the priority
374 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
375 pitl->SetPriority( GetMaximalPriorityWithoutLocking() + 1 );
376 pitl->SetUser( this );
378 if (pitl->Index()>=0)
381 mQueue.upsort(pitl->Index());
383 // Not read but not in queue = being read = ok
386 pitl->SetUser( this );
392 // Never requested before or unloaded
393 ImageToLoadPtr pitl =
394 new ImageToLoad(this,filename,
395 GetMaximalPriorityWithoutLocking() + 1);
403 // std::cout << "Waiting..."<<std::endl;
406 // Waiting that it is read
410 // std::cout << n++ << std::endl;
414 // wxMutexLocker lock(mMutex);
415 wxMutexLocker lock(GetMultiThreadImageReaderUserMutex());
416 if (mRequestedImage!=0)
418 return mRequestedImage;
427 //=====================================================================
429 //=====================================================================
430 void MultiThreadImageReader::SignalImageRead(ImageToLoadPtr p,
434 // std::cout << "MultiThreadImageReader::SignalImageRead" <<std::endl;
435 // std::cout << "this="<<this <<std::endl;
436 // std::cout << "user="<<p->GetUser() <<std::endl;
438 if ( p->GetUser() == this )
439 GetMultiThreadImageReaderUserMutex()->unlock();
441 p->GetUser()->MultiThreadImageReaderSendEvent
443 MultiThreadImageReaderUser::ImageLoaded,
447 AN ATTEMPT TO UNLOAD OLDEST IMAGE IF EXCEEDED A CERTAIN MEMORY QUOTA
451 GimmickMessage(5,"Image '"<<p->GetFilename()<<"' read"<<std::endl);
453 // wxMutexLocker lock(GetMultiThreadImageReaderUserMutex());
455 mUnloadQueue.insert(p);
456 p->GetImage()->UpdateInformation();
457 p->GetImage()->PropagateUpdateExtent();
458 long ImMem = p->GetImage()->GetEstimatedMemorySize();
461 GimmickMessage(5,"==> Image in memory = "<<mUnloadQueue.size()<<std::endl);
462 GimmickMessage(5,"==> Total mem = "<<mTotalMem<<" Ko"<<std::endl);
466 while (mTotalMem > mTotalMemMax)
469 " ! Exceeded max of "
470 << mTotalMemMax << " Ko : unloading oldest image ... "
472 if ( mUnloadQueue.size() <= 1 )
475 " Only one image : cannot load AND unload it !!"
480 ImageToLoadPtr unload = mUnloadQueue.remove_top();
481 MultiThreadImageReaderUser* user = unload->GetUser();
484 if ((user!=0)&&(user!=this))
486 user->GetMultiThreadImageReaderUserMutex().Lock();
490 std::string filename = unload->GetFilename();
492 GimmickMessage(5,"'" << filename << "'" << std::endl);
493 mTotalMem -= unload->GetImage()->GetEstimatedMemorySize();
495 GimmickMessage(5," ==> Total mem = "<<mTotalMem<<" Ko "<<std::endl);
499 // std::cout << "unlock..."<<std::endl;
500 // user->GetMultiThreadImageReaderUserMutex().Unlock();
501 // std::cout << "event"<<std::endl;
502 user->MultiThreadImageReaderSendEvent
504 MultiThreadImageReaderUser::ImageUnloaded,
506 // std::cout << "event ok"<<std::endl;
509 if (unload->Index()>=0)
511 // GimmickMessage(5,"still in queue"<<std::endl);
513 unload->Index() = -1;
516 ImageMapType::iterator it = mImages.find(unload);
517 if (it!=mImages.end())
521 // std::cout << "delete..."<<std::endl;
523 // std::cout << "delete ok."<<std::endl;
527 //=====================================================================
529 //=====================================================================
530 int MultiThreadImageReader::GetMaximalPriority()
532 QMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
533 return GetMaximalPriorityWithoutLocking();
535 //=====================================================================
538 //=====================================================================
539 int MultiThreadImageReader::GetMaximalPriorityWithoutLocking()
544 max = mQueue.top()->GetPriority();
546 if (mUnloadQueue.size()>0)
548 int max2 = mUnloadQueue.top()->GetPriority();
549 if (max2>max) max=max2;
553 //=====================================================================
556 //=====================================================================
557 //=====================================================================
558 //=====================================================================
559 //=====================================================================
561 //=====================================================================
562 void* ThreadedImageReader::Entry()
564 // std::cout << "### Thread "<<GetCurrentId()<<"::Entry()"
567 mMultiThreadImageReader->MultiThreadImageReaderSendEvent
569 MultiThreadImageReaderUser::ThreadedReaderStarted,
572 // While was not deleted
573 while (!isFinished())
575 //std::cout << "### Thread "<<GetCurrentId()<<" still alive" << std::endl;
578 mMultiThreadImageReader->MultiThreadImageReaderEventLock();
581 if (mMultiThreadImageReader->mQueue.size()>0)
583 MultiThreadImageReader::ImageToLoadPtr i =
584 mMultiThreadImageReader->mQueue.remove_top();
586 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();
590 // std::cout << "### Thread "<<GetCurrentId()<<" : reading '"
591 // << i->GetFilename() << "'" << std::endl;
594 vtkImageData* im = Read(i->GetFilename());
596 // Store it in the map
597 mMultiThreadImageReader->MultiThreadImageReaderEventLock();
599 MultiThreadImageReader::ImageToLoad itl(0,i->GetFilename());
600 MultiThreadImageReader::ImageMapType::iterator it =
601 mMultiThreadImageReader->mImages.find(&itl);
602 MultiThreadImageReader::ImageToLoadPtr
603 pitl = const_cast<MultiThreadImageReader::ImageToLoadPtr>
606 mMultiThreadImageReader->SignalImageRead(pitl,true);//i->GetFilename());
607 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock(); //mMutex.Unlock();
609 // std::cout << "### Thread "<<GetCurrentId()<<" : reading '"
610 // << i->GetFilename() << "' : DONE" << std::endl;
615 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();
617 // Wait a little to avoid blocking
621 // std::cout << "### Thread "<<GetCurrentId()<<" stopping"
626 //=====================================================================
628 //=====================================================================
629 void ThreadedImageReader::OnExit()
631 mMultiThreadImageReader->MultiThreadImageReaderSendEvent
633 MultiThreadImageReaderUser::ThreadedReaderStopped,
636 //=====================================================================
638 //=====================================================================
639 vtkImageData* ThreadedImageReader::Read(const std::string& filename)
641 return mReader.ReadImage(filename);
643 //=====================================================================
645 } // namespace creaImageIO