public void QueueThumbnailUpdate(IThumbnailProvider updateMe, int thumbSideLength, ThumbnailReadyHandler callback) { if (thumbSideLength < 1) { throw new ArgumentOutOfRangeException("thumbSideLength", "must be greater than or equal to 1"); } lock (this.updateLock) { bool doIt = false; ThumbnailStackItem addMe = new ThumbnailStackItem(updateMe, callback, thumbSideLength); if (this.renderQueue.Count == 0) { doIt = true; } else { ThumbnailStackItem top = this.renderQueue.Peek(); if (addMe != top) { doIt = true; } } // Only add this item to the queue if the item is not already at the top of the queue if (doIt) { this.renderQueue.Push(addMe); } Monitor.Pulse(this.updateLock); } }
private void RenderThreadImpl() { while (true) { ThumbnailStackItem renderMe = new ThumbnailStackItem(); // Wait for either a new item to render, or a signal to quit lock (this.updateLock) { if (this.quitRenderThread) { return; } while (this.renderQueue.Count == 0) { Monitor.Wait(this.updateLock); if (this.quitRenderThread) { return; } } this.renderingInactive.Reset(); renderMe = this.renderQueue.Pop(); } // Sleep for a short while. Our main goal is to ensure that the // item is not re-queued for updating very soon after we start // rendering it. Thread.Sleep(this.updateLatency); bool doRender = true; // While we were asleep, ensure that this same item has not been // re-added to the render queue. If it has, we will skip rendering // it. This covers the scenario where an item is updated many // times in rapid succession, in which case we want to wait until // the item has settled down before spending any CPU time rendering // its thumbnail. lock (this.updateLock) { if (this.quitRenderThread) { return; } if (this.renderQueue.Count > 0) { if (renderMe == this.renderQueue.Peek()) { doRender = false; } } } if (doRender) { try { Surface thumb; using (new ThreadBackground(ThreadBackgroundFlags.All)) { thumb = renderMe.First.RenderThumbnail(renderMe.Third); } // If this same item has already been re-queued for an update, then throw // away what we just rendered. Otherwise we may get flickering as the // item was being updated while we were rendering the preview. bool discard = false; lock (this.updateLock) { if (this.quitRenderThread) { thumb.Dispose(); thumb = null; return; } if (this.renderQueue.Count > 0) { if (renderMe == this.renderQueue.Peek()) { discard = true; thumb.Dispose(); thumb = null; } } } if (!discard) { OnThumbnailReady(renderMe.First, renderMe.Second, thumb); } } catch (Exception ex) { try { Tracing.Ping("Exception in RenderThread while calling CreateThumbnail: " + ex.ToString()); } catch (Exception) { } } } this.renderingInactive.Set(); } }