Alfredo Braunstein wrote: > Ah, I see. A call to startLoading within LoadNext() can summon other > redraws and end up in a touch(), maybe? In this case, the bucket is needed > but not the locking. I will try this.
And it works like a charm. I've tried to correct also the withespace, and I'm attaching again the two new files (the patch sent last time being still valid and has to be applied to use this). Bye, Alfredo.
/** * \file LoaderQueue.C * This file is part of LyX, the document processor. * Licence details can be found in the file COPYING. * * \author Alfredo Braunstein * * Full author contact details are available in file CREDITS */ #include "LoaderQueue.h" #include "debug.h" #include <boost/bind.hpp> namespace grfx { LoaderQueue & LoaderQueue::get() { static LoaderQueue singleton; return singleton; } void LoaderQueue::loadNext() { emptyBucket(); lyxerr[Debug::GRAPHICS] << "LoaderQueue: " << cache_queue_.size() << " items in the queue" << endl; int counter = 10; while (cache_queue_.size() && counter--) { if(cache_queue_.front()->status() == WaitingToLoad) cache_queue_.front()->startLoading(); cache_set_.erase(cache_queue_.front()); cache_queue_.pop_front(); } if (cache_queue_.size() || bucket_.size()) { startLoader(); } else { stopLoader(); } } LoaderQueue::LoaderQueue() : timer(100, Timeout::ONETIME), running_(false) { timer.timeout.connect(boost::bind(&LoaderQueue::loadNext, this)); } void LoaderQueue::emptyBucket() { lyxerr[Debug::GRAPHICS] << "LoaderQueue: emptying bucket" << endl; while (! bucket_.empty()) { addToQueue(bucket_.front()); bucket_.pop(); } } void LoaderQueue::startLoader() { lyxerr[Debug::GRAPHICS] << "LoaderQueue: waking up" << endl; running_ = true ; timer.start(); } void LoaderQueue::stopLoader() { timer.stop(); running_ = false ; lyxerr[Debug::GRAPHICS] << "LoaderQueue: I'm going to sleep" << endl; } bool LoaderQueue::running() const { return running_ ; } void LoaderQueue::touch(Cache::ItemPtr const & item) { if (! running_) startLoader(); bucket_.push(item); } void LoaderQueue::addToQueue(Cache::ItemPtr const & item) { if (! cache_set_.insert(item).second) { list<Cache::ItemPtr>::iterator it = cache_queue_.begin(); list<Cache::ItemPtr>::iterator end = cache_queue_.end(); it = std::find(it, end, item); if (it != end) cache_queue_.erase(it); } cache_queue_.push_front(item); } } // namespace grfx
// -*- C++ -*- /** * \file LoaderQueue.h * This file is part of LyX, the document processor. * Licence details can be found in the file COPYING. * * \author Alfredo Braunstein * * Full author contact details are available in file CREDITS. * * This implements a threaded service queue which loads images on background. * In order to request an image loading you call touch() with the pointer to * the cached image. Then it will try to satisfy the request as soon as * posible (that's it: after finishing an eventual loading on progress) * touch() returns inmediately, in order not tu disrupt the flow of the main * thread. * The service thread is the method loadNext(). It's actually not a thread, * but implemented with a timer that comes back every x msec. */ #ifndef LOADERQUEUE_H #define LOADERQUEUE_H #include "GraphicsCache.h" #include "GraphicsCacheItem.h" #include "frontends/Timeout.h" #include <set> #include <queue> namespace grfx { class LoaderQueue { public: //use this to request a loading void touch(Cache::ItemPtr const & item); //query if the clock is ticking bool running() const; //get the and only instance of the class static LoaderQueue & get(); private: //this class is a singleton class... use LoaderQueue::get() instead LoaderQueue(); //in-progress loading queue (elements are unique here) std::list<Cache::ItemPtr> cache_queue_; //makes faster the insertion of new elements std::set<Cache::ItemPtr> cache_set_; //newly touched element go here, loadNext move them to cache_queue_ std::queue<Cache::ItemPtr> bucket_; // Timeout timer; // bool running_; //moves bucket_ to cache_queue_ void emptyBucket(); //adds or reprioritizes one element in cache_queue_ void addToQueue(Cache::ItemPtr const & item); //this is the 'threaded' method, that does the loading in background void loadNext(); // void startLoader(); // void stopLoader(); }; } // namespace grfx #endif // LOADERQUEUE_H