/// <summary> /// Worker thread procedure which implements the main animation loop. /// NOTE: This is the ONLY code the worker thread executes, keeping it in one method helps better understand /// any synchronization issues. /// WARNING: Also, this is the only place where ImageInfo objects (not the contained image object) are modified, /// so no access synchronization is required to modify them. /// </summary> private static void AnimateImages() { Debug.Assert(s_imageInfoList != null, "Null images list"); Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); while (true) { Thread.Sleep(40); // Because Thread.Sleep is not accurate, capture how much time has actually elapsed during the animation long timeElapsed = stopwatch.ElapsedMilliseconds; stopwatch.Restart(); // Acquire reader-lock to access imageInfoList, elements in the list can be modified w/o needing a writer-lock. // Observe that we don't need to check if the thread is waiting or a writer lock here since the thread this // method runs in never acquires a writer lock. s_rwImgListLock.AcquireReaderLock(Timeout.Infinite); try { for (int i = 0; i < s_imageInfoList.Count; i++) { ImageInfo imageInfo = s_imageInfoList[i]; if (imageInfo.Animated) { imageInfo.AdvanceAnimationBy(timeElapsed); if (imageInfo.FrameDirty) { s_anyFrameDirty = true; } } } } finally { s_rwImgListLock.ReleaseReaderLock(); } } }