Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /////////////////////////////////////////////////////////////////////////////////
- // paint.net //
- // Copyright (C) dotPDN LLC, Rick Brewster, and contributors. //
- // All Rights Reserved. //
- /////////////////////////////////////////////////////////////////////////////////
- using System;
- using System.Threading;
- namespace PaintDotNet.Threading
- {
- /// <summary>
- /// Implements a critical section that can be unlocked precisely once. This is useful
- /// for guarding lazy initialization and avoiding a lock convoy once the value is
- /// published.
- ///
- /// The first thread that calls Enter will acquire the lock, and then all other threads
- /// will block until that first thread calls Exit. At that point, all threads will be
- /// released and all further calls into Enter will return immediately. This helps to
- /// avoid a lock convoy once the lock is released by the first thread.
- /// </summary>
- public sealed class SingleUseCriticalSection
- {
- private const int invalidThreadID = -0x0b4db33f; // thread IDs can't be negative
- private int enterCount;
- private int exitCount;
- private volatile ManualResetEvent resetEvent;
- private int ownerThreadID = invalidThreadID;
- public SingleUseCriticalSection()
- {
- this.enterCount = 0;
- this.resetEvent = new ManualResetEvent(false);
- }
- public override void Enter()
- {
- if (Interlocked.Increment(ref this.enterCount) == 1)
- {
- this.ownerThreadID = Thread.CurrentThread.ManagedThreadId;
- }
- else if (Thread.CurrentThread.ManagedThreadId == this.ownerThreadID)
- {
- // Support re-entrant access on the same thread.
- // We won't necessarily get a correct value for this if we're not on the thread
- // that entered the lock. It's possible that 2 threads race to call Enter(),
- // one will get the lock and set the thread ID, and the other will call Enter()
- // and get invalidThreadID for the thread ID. However, since that isn't a valid
- // value for a managed thread ID, this will be okay.
- }
- else
- {
- ManualResetEvent resetEvent = this.resetEvent;
- if (resetEvent != null)
- {
- resetEvent.WaitOne();
- }
- }
- }
- public override void Exit()
- {
- if (Interlocked.Increment(ref this.exitCount) == 1)
- {
- ManualResetEvent resetEvent = this.resetEvent;
- this.resetEvent = null;
- resetEvent.Set();
- }
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement