A game framework written with osu! in mind.
at master 2.7 kB view raw
1// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. 2// See the LICENCE file in the repository root for full licence text. 3 4using System; 5using System.Collections.Generic; 6using System.Threading; 7using System.Threading.Tasks; 8using osu.Framework.Statistics; 9 10namespace osu.Framework.Allocation 11{ 12 /// <summary> 13 /// A queue which batches object disposal on threadpool threads. 14 /// </summary> 15 internal static class AsyncDisposalQueue 16 { 17 private static readonly GlobalStatistic<string> last_disposal = GlobalStatistics.Get<string>("Drawable", "Last disposal"); 18 19 private static readonly List<IDisposable> disposal_queue = new List<IDisposable>(); 20 21 private static Task runTask; 22 23 private static readonly ManualResetEventSlim processing_reset_event = new ManualResetEventSlim(true); 24 25 private static int runningTasks; 26 27 /// <summary> 28 /// Enqueue a disposable object for asynchronous disposal. 29 /// </summary> 30 /// <param name="disposable">The object to dispose.</param> 31 public static void Enqueue(IDisposable disposable) 32 { 33 lock (disposal_queue) 34 { 35 disposal_queue.Add(disposable); 36 37 if (runTask?.Status < TaskStatus.Running) 38 return; 39 40 Interlocked.Increment(ref runningTasks); 41 processing_reset_event.Reset(); 42 } 43 44 runTask = Task.Run(() => 45 { 46 try 47 { 48 IDisposable[] itemsToDispose; 49 50 lock (disposal_queue) 51 { 52 itemsToDispose = disposal_queue.ToArray(); 53 disposal_queue.Clear(); 54 } 55 56 for (int i = 0; i < itemsToDispose.Length; i++) 57 { 58 ref var item = ref itemsToDispose[i]; 59 60 last_disposal.Value = item.ToString(); 61 item.Dispose(); 62 63 item = null; 64 } 65 } 66 finally 67 { 68 lock (disposal_queue) 69 { 70 if (Interlocked.Decrement(ref runningTasks) == 0) 71 processing_reset_event.Set(); 72 } 73 } 74 }); 75 } 76 77 /// <summary> 78 /// Wait until all items in the async disposal queue have been flushed. 79 /// Will wait for a maximum of 10 seconds. 80 /// </summary> 81 public static void WaitForEmpty() => processing_reset_event.Wait(TimeSpan.FromSeconds(10)); 82 } 83}