Created
May 20, 2015 21:52
-
-
Save cameronism/15058503a3d9b3565e7a to your computer and use it in GitHub Desktop.
Safe helper to defer setup until needed and teardown until after a delay
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /// <summary> | |
| /// Safe helper to defer setup until needed and teardown until after a delay | |
| /// </summary> | |
| /// <remarks> | |
| /// You're on your own if setup or teardown throws or if Dispose is not called on each Acquire result | |
| /// </remarks> | |
| public class DelayedTeardown | |
| { | |
| // -1 indicates that setup needs to be run | |
| private int _count = -1; | |
| private object _lock = new object(); | |
| private Timer _timer; | |
| private int _delay; | |
| private Action _teardown; | |
| private Action _setup; | |
| public struct Disposable : IDisposable | |
| { | |
| DelayedTeardown _parent; | |
| /// <summary>Be kind. Don't call this. Get it from Acquire</summary> | |
| internal Disposable(DelayedTeardown instance) | |
| { | |
| _parent = instance; | |
| } | |
| public void Dispose() | |
| { | |
| _parent.Release(); | |
| } | |
| } | |
| public DelayedTeardown(TimeSpan delay, Action setup, Action teardown) | |
| { | |
| _delay = (int)delay.TotalMilliseconds; | |
| _teardown = teardown; | |
| _setup = setup; | |
| _timer = new Timer(Teardown); | |
| } | |
| private void Teardown(object state) | |
| { | |
| lock (_lock) | |
| { | |
| if (_count > 0) | |
| return; | |
| _teardown.Invoke(); | |
| _count = -1; | |
| } | |
| } | |
| private void Release() | |
| { | |
| lock (_lock) | |
| { | |
| if (--_count == 0) | |
| _timer.Change(_delay, Timeout.Infinite); | |
| } | |
| } | |
| public Disposable Acquire() | |
| { | |
| lock (_lock) | |
| { | |
| if (_count == -1) | |
| { | |
| _setup.Invoke(); | |
| _count = 1; | |
| } | |
| else | |
| { | |
| _count++; | |
| } | |
| } | |
| return new Disposable(this); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| var counter = new DelayedTeardown(TimeSpan.FromSeconds(0.5), () => "setup".Dump(), () => "teardown".Dump()); | |
| for (int i = 0; i < 10; i++) | |
| { | |
| ThreadPool.QueueUserWorkItem(state => | |
| { | |
| using (counter.Acquire()) | |
| { | |
| state.Dump(); | |
| } | |
| }, i.ToString()); | |
| } | |
| // let teardown happen in the middle around half the time (on my machine) | |
| Thread.Sleep(517); | |
| for (int i = 0; i < 10; i++) | |
| { | |
| ThreadPool.QueueUserWorkItem(state => | |
| { | |
| using (counter.Acquire()) | |
| { | |
| state.Dump(); | |
| } | |
| }, i.ToString()); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment