00001 #include <creaImageIOQMultiThreadImageReader.h>
00002 #include <creaImageIOImageReader.h>
00003
00004 #include <QThread>
00005 #include <creaImageIOSystem.h>
00006
00007 #include <creaImageIOGimmick.h>
00008 #ifdef _DEBUG
00009 #define new DEBUG_NEW
00010 #endif
00011 namespace creaImageIO
00012 {
00013
00014
00015 void MultiThreadImageReaderUser::MultiThreadImageReaderSendEvent
00016 ( const std::string& filename,
00017 EventType type,
00018 vtkImageData* image)
00019 {
00020 QMutexLocker lock(&mMultiThreadImageReaderUserMutex);
00021
00022 this->OnMultiThreadImageReaderEvent(filename,type,image);
00023 }
00024
00025
00026
00027 class ThreadedImageReader: public QThread
00028 {
00029 public:
00030 ThreadedImageReader(MultiThreadImageReader* tir) :
00031 mMultiThreadImageReader(tir)
00032 {}
00033
00034 void* Entry();
00035 void OnExit();
00036
00037 vtkImageData* Read(const std::string& filename);
00038
00039 struct deleter
00040 {
00041 void operator()(ThreadedImageReader* p)
00042 {
00043 delete p;
00044 }
00045 };
00046 friend struct deleter;
00047
00048
00049 private:
00050 ImageReader mReader;
00051 MultiThreadImageReader* mMultiThreadImageReader;
00052
00053 };
00054
00055
00056
00057
00058
00059 MultiThreadImageReader::MultiThreadImageReader(int number_of_threads)
00060 :
00061 mReader(0),
00062 mTotalMem(0),
00063 mTotalMemMax(1000000)
00064 {
00065
00066
00067
00068 mDone = false;
00069
00070 for (int i=0; i<number_of_threads; i++)
00071 {
00072
00073 boost::shared_ptr<ThreadedImageReader> t(new ThreadedImageReader(this), ThreadedImageReader::deleter());
00074 mThreadedImageReaderList.push_back(t);
00075 std::cout << " ===> Thread "<<i
00076 <<" successfully added"<< std::endl;
00077 }
00078 mNumberOfThreadedReadersRunning = 0;
00079
00080 mQueue.set(mComparator);
00081 mQueue.set(mIndexer);
00082
00083
00084
00085
00086 mReader = new ImageReader();
00087
00088 }
00089
00090
00091
00092
00093 bool MultiThreadImageReader::Start()
00094 {
00095
00096
00097
00098 if (mNumberOfThreadedReadersRunning > 0) return true;
00099
00100 ThreadedImageReaderListType::iterator i;
00101 for (i =mThreadedImageReaderList.begin();
00102 i!=mThreadedImageReaderList.end();
00103 i++)
00104 {
00105 (*i)->start();
00106 if ( !(*i)->isRunning() )
00107 {
00108 std::cout << "ERROR starting a thread"<< std::endl;
00109 return false;
00110 }
00111 else
00112 {
00113 std::cout << " ===> Thread "<<(*i)->currentThreadId()
00114 <<" successfully created"<< std::endl;
00115
00116 }
00117 }
00118 QMutexLocker locker(GetMultiThreadImageReaderUserMutex());
00119
00120
00121
00122 return true;
00123 }
00124
00125
00126
00127 void MultiThreadImageReader::Stop()
00128 {
00129
00130
00131
00132 if (mDone) return;
00133
00134 ThreadedImageReaderListType::iterator i;
00135 for (i =mThreadedImageReaderList.begin();
00136 i!=mThreadedImageReaderList.end();
00137 i++)
00138 { std::cout << " ===> Thread "<<(*i)->currentThreadId()
00139 <<" successfully stopped"<< std::endl;
00140 if(!(*i)->isFinished())
00141 {(*i)->wait();
00142 (*i).reset();
00143
00144 }
00145 }
00146 mThreadedImageReaderList.clear();
00147
00148
00149
00150
00151
00152
00153 do
00154 {
00155
00156
00157
00158 {
00159 QMutexLocker locker(GetMultiThreadImageReaderUserMutex());
00160
00161
00162
00163 if (mNumberOfThreadedReadersRunning <= 0)
00164 {
00165 break;
00166 }
00167 }
00168 }
00169 while (true);
00170
00171
00172 ImageMapType::iterator j;
00173 for (j =mImages.begin();
00174 j!=mImages.end();
00175 ++j)
00176
00177 {
00178 delete j->first;
00179 }
00180 mImages.clear();
00181 mDone = true;
00182 }
00183
00184
00185
00186 MultiThreadImageReader::~MultiThreadImageReader()
00187 {
00188
00189
00190 Stop();
00191 if (mReader) delete mReader;
00192 mThreadedImageReaderList.clear();
00193 }
00194
00195
00196
00197 void MultiThreadImageReader::UpdateUnloadPriority(ImageToLoadPtr p,
00198 int priority)
00199 {
00200
00201 if (p->UnloadIndex()<0) return;
00202 int old_prio = p->GetPriority();
00203 if (priority > old_prio)
00204 {
00205 p->SetPriority(priority);
00206 mUnloadQueue.downsort(p->UnloadIndex());
00207 }
00208 else if ( old_prio > priority )
00209 {
00210 p->SetPriority(priority);
00211 mUnloadQueue.upsort(p->UnloadIndex());
00212 }
00213 }
00214
00215
00216 void MultiThreadImageReader::getAttributes(const std::string filename,
00217 std::map <std::string , std::string> &infos,std::vector<std::string> i_attr)
00218 {
00219 mReader->getAttributes(filename, infos, i_attr);
00220 }
00221
00222
00223 void MultiThreadImageReader::Request( MultiThreadImageReaderUser* user,
00224 const std::string& filename,
00225 int priority )
00226 {
00227 QMutexLocker lock(GetMultiThreadImageReaderUserMutex());
00228
00229 if (mNumberOfThreadedReadersRunning==0)
00230
00231 {
00232
00233 ImageToLoad itl(user,filename);
00234 ImageMapType::iterator i = mImages.find(&itl);
00235 if (i!=mImages.end())
00236 {
00237 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
00238
00239 if (pitl->GetImage() != 0)
00240 {
00241
00242 pitl->SetUser(user);
00243 UpdateUnloadPriority(pitl,priority);
00244 SignalImageRead(pitl,false);
00245 return;
00246 }
00247 }
00248 ImageToLoadPtr pitl = new ImageToLoad(user,filename,0);
00249 mImages[pitl] = 0;
00250 pitl->SetImage(mReader->ReadImage(filename));
00251 UpdateUnloadPriority(pitl,priority);
00252 SignalImageRead(pitl,true);
00253
00254 return;
00255 }
00256
00257 ImageToLoad itl(user,filename);
00258 ImageMapType::iterator i = mImages.find(&itl);
00259 if (i!=mImages.end())
00260 {
00261
00262 if (i->first->GetImage() != 0)
00263 {
00264
00265 UpdateUnloadPriority(i->first,priority);
00266 SignalImageRead(i->first,false);
00267 return;
00268 }
00270 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
00271 pitl->SetPriority(priority);
00272
00273 if (pitl->Index()>=0)
00274 {
00275
00276 mQueue.upsort(pitl->Index());
00277 }
00278
00279 else
00280 {
00281
00282 }
00283 }
00284 else
00285 {
00286
00287 ImageToLoadPtr pitl = new ImageToLoad(user,filename,priority);
00288 mImages[pitl] = 0;
00289 mQueue.insert(pitl);
00290 }
00291 }
00292
00293
00294
00295 void MultiThreadImageReader::OnMultiThreadImageReaderEvent
00296 (const std::string& filename,
00297 MultiThreadImageReaderUser::EventType e,
00298 vtkImageData* image)
00299 {
00300 if ((e==MultiThreadImageReaderUser::ImageLoaded) &&
00301 (filename == mRequestedFilename))
00302 {
00303 mRequestedImage = image;
00304 }
00305 else if (e==MultiThreadImageReaderUser::ThreadedReaderStarted)
00306 {
00307 mNumberOfThreadedReadersRunning++;
00308
00309 }
00310 else if (e==MultiThreadImageReaderUser::ThreadedReaderStopped)
00311 {
00312
00313 mNumberOfThreadedReadersRunning--;
00314
00315 }
00316 }
00317
00318
00319
00320 vtkImageData* MultiThreadImageReader::GetImage(const std::string& filename)
00321 {
00322
00323
00324
00325
00326 do
00327 {
00328
00329
00330
00331
00332
00333
00334
00335
00336 if (true)
00337 {
00338 ImageToLoad itl(this,filename);
00339 ImageMapType::iterator i = mImages.find(&itl);
00340 if (i!=mImages.end())
00341 {
00342 ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
00343
00344 if (pitl->GetImage() != 0)
00345 {
00346
00347 UpdateUnloadPriority(pitl,
00348 GetMaximalPriorityWithoutLocking()+1);
00349 return pitl->GetImage();
00350 }
00351 }
00352 ImageToLoadPtr pitl = new ImageToLoad(this,filename,0);
00353 mImages[pitl] = 0;
00354 pitl->SetImage(mReader->ReadImage(filename));
00355 UpdateUnloadPriority(pitl,
00356 GetMaximalPriorityWithoutLocking()+1);
00357 return pitl->GetImage();
00358 }
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400 }
00401 while (0);
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426 }
00427
00428
00429
00430 void MultiThreadImageReader::SignalImageRead(ImageToLoadPtr p,
00431 bool purge)
00432 {
00433
00434
00435
00436
00437
00438 if ( p->GetUser() == this )
00439 GetMultiThreadImageReaderUserMutex()->unlock();
00440
00441 p->GetUser()->MultiThreadImageReaderSendEvent
00442 (p->GetFilename(),
00443 MultiThreadImageReaderUser::ImageLoaded,
00444 p->GetImage());
00445
00446
00447
00448
00449
00450 if (!purge) return;
00451 GimmickMessage(5,"Image '"<<p->GetFilename()<<"' read"<<std::endl);
00452
00453
00454
00455 mUnloadQueue.insert(p);
00456 p->GetImage()->UpdateInformation();
00457 p->GetImage()->PropagateUpdateExtent();
00458 long ImMem = p->GetImage()->GetEstimatedMemorySize();
00459 mTotalMem += ImMem;
00460
00461 GimmickMessage(5,"==> Image in memory = "<<mUnloadQueue.size()<<std::endl);
00462 GimmickMessage(5,"==> Total mem = "<<mTotalMem<<" Ko"<<std::endl);
00463
00464
00465
00466 while (mTotalMem > mTotalMemMax)
00467 {
00468 GimmickMessage(5,
00469 " ! Exceeded max of "
00470 << mTotalMemMax << " Ko : unloading oldest image ... "
00471 << std::endl);
00472 if ( mUnloadQueue.size() <= 1 )
00473 {
00474 GimmickMessage(5,
00475 " Only one image : cannot load AND unload it !!"
00476 <<std::endl);
00477 break;
00478
00479 }
00480 ImageToLoadPtr unload = mUnloadQueue.remove_top();
00481 MultiThreadImageReaderUser* user = unload->GetUser();
00482
00483
00484
00485
00486
00487
00488
00489
00490 std::string filename = unload->GetFilename();
00491
00492 GimmickMessage(5,"'" << filename << "'" << std::endl);
00493 mTotalMem -= unload->GetImage()->GetEstimatedMemorySize();
00494
00495 GimmickMessage(5," ==> Total mem = "<<mTotalMem<<" Ko "<<std::endl);
00496
00497 if (user!=0)
00498 {
00499
00500
00501
00502 user->MultiThreadImageReaderSendEvent
00503 (filename,
00504 MultiThreadImageReaderUser::ImageUnloaded,
00505 0);
00506
00507 }
00508
00509 if (unload->Index()>=0)
00510 {
00511
00512 }
00513 unload->Index() = -1;
00514
00515
00516 ImageMapType::iterator it = mImages.find(unload);
00517 if (it!=mImages.end())
00518 {
00519 mImages.erase(it);
00520 }
00521
00522 delete unload;
00523
00524
00525 }
00526 }
00527
00528
00529
00530 int MultiThreadImageReader::GetMaximalPriority()
00531 {
00532 QMutexLocker lock(GetMultiThreadImageReaderUserMutex());
00533 return GetMaximalPriorityWithoutLocking();
00534 }
00535
00536
00537
00538
00539 int MultiThreadImageReader::GetMaximalPriorityWithoutLocking()
00540 {
00541 long max = 0;
00542 if (mQueue.size()>0)
00543 {
00544 max = mQueue.top()->GetPriority();
00545 }
00546 if (mUnloadQueue.size()>0)
00547 {
00548 int max2 = mUnloadQueue.top()->GetPriority();
00549 if (max2>max) max=max2;
00550 }
00551 return max;
00552 }
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562 void* ThreadedImageReader::Entry()
00563 {
00564
00565
00566
00567 mMultiThreadImageReader->MultiThreadImageReaderSendEvent
00568 ("",
00569 MultiThreadImageReaderUser::ThreadedReaderStarted,
00570 0);
00571
00572
00573 while (!isFinished())
00574 {
00575
00576
00577
00578 mMultiThreadImageReader->MultiThreadImageReaderEventLock();
00579
00580
00581 if (mMultiThreadImageReader->mQueue.size()>0)
00582 {
00583 MultiThreadImageReader::ImageToLoadPtr i =
00584 mMultiThreadImageReader->mQueue.remove_top();
00585
00586 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();
00587
00588
00589
00590
00591
00592
00593
00594 vtkImageData* im = Read(i->GetFilename());
00595
00596
00597 mMultiThreadImageReader->MultiThreadImageReaderEventLock();
00598
00599 MultiThreadImageReader::ImageToLoad itl(0,i->GetFilename());
00600 MultiThreadImageReader::ImageMapType::iterator it =
00601 mMultiThreadImageReader->mImages.find(&itl);
00602 MultiThreadImageReader::ImageToLoadPtr
00603 pitl = const_cast<MultiThreadImageReader::ImageToLoadPtr>
00604 (it->first);
00605 pitl->SetImage(im);
00606 mMultiThreadImageReader->SignalImageRead(pitl,true);
00607 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();
00608
00609
00610
00611
00612 }
00613 else
00614 {
00615 mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();
00616
00617
00618 Sleep(10);
00619 }
00620 };
00621
00622
00623
00624 return 0;
00625 }
00626
00627
00628
00629 void ThreadedImageReader::OnExit()
00630 {
00631 mMultiThreadImageReader->MultiThreadImageReaderSendEvent
00632 ("",
00633 MultiThreadImageReaderUser::ThreadedReaderStopped,
00634 0);
00635 }
00636
00637
00638
00639 vtkImageData* ThreadedImageReader::Read(const std::string& filename)
00640 {
00641 return mReader.ReadImage(filename);
00642 }
00643
00644
00645 }