A second option for LoaderQueue. I've left the previous interface untouched, but changed a little the implementation. Now touch() doesn't add directly the image pointer to the queue, but it adds it to an input bucket (implemented as a plain queue) without any checking and returns inmediately. Then on the 'threaded' method LoadNext we empty the input bucket into the queue, with all uniqueness and reprioritization checking. This implementation avoids completely having to lock the data, and so any posibility of losing time on the main thread. The startup time should be shorter also.
I have to solve at least one problem: the graphics insets have startLoading called in document order, from first to last. Then they are added to the queue in inversed order, and start loading from last to first. Maybe we have to bypass this reprioritizing mechanism on startup somehow? Any clue on how to solve this please? (there are other remaining things if ever this gets incorporated: like to where the LoaderQueue class belongs (BufferView?). Does it deserves its own file, and so) Regards, Alfredo PS: As before, please correct without mercy but being nice...
Index: GraphicsLoader.C =================================================================== RCS file: /cvs/lyx/lyx-devel/src/graphics/GraphicsLoader.C,v retrieving revision 1.12 diff -u -r1.12 GraphicsLoader.C --- GraphicsLoader.C 2003/02/13 16:53:00 1.12 +++ GraphicsLoader.C 2003/02/20 12:27:32 @@ -28,9 +28,112 @@ #include <boost/signals/trackable.hpp> #include <list> +#include <set> +#include <queue> +#include <algorithm> namespace grfx { +class LoaderQueue { +public: + LoaderQueue(); + void touch(Cache::ItemPtr item); + bool running(); +private: + std::list<Cache::ItemPtr> cache_queue_; + std::set<Cache::ItemPtr> cache_set_; + std::queue<Cache::ItemPtr> bucket1_; + std::queue<Cache::ItemPtr> bucket2_; + Timeout timer; + bool running_; + + void emptyBucket(); + void addToQueue(Cache::ItemPtr item); + void loadNext(); + void startLoader(); + void stopLoader(); +}; + +void LoaderQueue::loadNext() +{ + emptyBucket(); + cout << cache_queue_.size() + << " items in the queue" << endl; + + if ( cache_queue_.size() ) { + cache_queue_.front()->startLoading(); + cache_set_.erase(cache_queue_.front()); + cache_queue_.pop_front(); + } + if (cache_queue_.size() || bucket1_.size()) { + startLoader(); + } else { + stopLoader(); + } +} + +LoaderQueue::LoaderQueue() : timer( 100 , Timeout::ONETIME ), + running_( false ) +{ + timer.timeout.connect( boost::bind( &LoaderQueue::loadNext, this)); +} + +void LoaderQueue::emptyBucket() +{ + cout << "emptying bucket" << endl; + swap(bucket1_, bucket2_); + while (! bucket2_.empty()) { + addToQueue(bucket2_.front()); + bucket2_.pop(); + } +} + +void LoaderQueue::startLoader() +{ + cout << "waking up" << endl; + running_ = true ; + timer.start(); +} + +void LoaderQueue::stopLoader() +{ + timer.stop(); + running_ = false ; + cout << "going to sleep" << endl; +} + +bool LoaderQueue::running() +{ + return running_ ; +} + +void LoaderQueue::touch(Cache::ItemPtr item) +{ + if ( ! running_ ) + startLoader(); + bucket1_.push(item); +} + + +void LoaderQueue::addToQueue(Cache::ItemPtr 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) { + cout << "key not found!" << endl; + } else + cache_queue_.erase( it ); + } + cache_queue_.push_front( item ); +} + +LoaderQueue LQ; + struct Loader::Impl : boost::signals::trackable { /// Impl(Params const &); @@ -66,8 +169,6 @@ /// Params params_; - /// - Timeout timer; // Multiple Insets can share the same image typedef std::list<Inset const *> InsetList; /// @@ -196,10 +297,8 @@ Loader::Impl::Impl(Params const & params) - : status_(WaitingToLoad), params_(params), - timer(2000, Timeout::ONETIME) + : status_(WaitingToLoad), params_(params) { - timer.timeout.connect(boost::bind(&Impl::checkedLoading, this)); } @@ -293,7 +392,7 @@ void Loader::Impl::startLoading(Inset const & inset, BufferView const & bv) { - if (status_ != WaitingToLoad || timer.running()) + if (status_ != WaitingToLoad) return; InsetList::const_iterator it = insets.begin(); @@ -302,8 +401,7 @@ if (it == end) insets.push_back(&inset); view = bv.owner()->view(); - - timer.start(); + LQ.touch(cached_item_); }