Skip to content

Commit 75c4007

Browse files
committed
Add SemaphoreSlimContext class
1 parent d893a1e commit 75c4007

File tree

2 files changed

+181
-0
lines changed

2 files changed

+181
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
using System;
2+
using System.Diagnostics;
3+
using System.Threading;
4+
5+
namespace THNETII.Common.Threading
6+
{
7+
public class SemaphoreSlimContext : IDisposable
8+
{
9+
private readonly SemaphoreSlim semaphore;
10+
11+
protected int ReleaseCount { get; }
12+
13+
private SemaphoreSlimContext(SemaphoreSlim semaphore, int releaseCount, bool verify)
14+
{
15+
Debug.Assert(!verify, nameof(verify) + " is not false.");
16+
this.semaphore = semaphore;
17+
ReleaseCount = releaseCount;
18+
}
19+
20+
protected SemaphoreSlimContext(SemaphoreSlim semaphore,
21+
int releaseCount = 1)
22+
: this(
23+
semaphore ?? throw new ArgumentNullException(nameof(semaphore)),
24+
releaseCount >= 1 ? releaseCount : throw new ArgumentOutOfRangeException(nameof(releaseCount), releaseCount, nameof(releaseCount) + " is less than 1"),
25+
verify: false
26+
)
27+
{ }
28+
29+
internal static SemaphoreSlimContext CreateNoVerify(SemaphoreSlim semaphore,
30+
int releaseCount = 1) =>
31+
new SemaphoreSlimContext(semaphore, releaseCount, verify: false);
32+
33+
#region IDisposable Support
34+
private int disposedValue = 0; // To detect redundant calls
35+
36+
protected virtual void Dispose(bool disposing)
37+
{
38+
if (Interlocked.Exchange(ref disposedValue, 1) == 0)
39+
{
40+
if (disposing)
41+
{
42+
semaphore?.Release(ReleaseCount);
43+
}
44+
}
45+
}
46+
47+
public void Dispose()
48+
{
49+
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
50+
Dispose(true);
51+
GC.SuppressFinalize(this);
52+
}
53+
54+
~SemaphoreSlimContext()
55+
{
56+
Dispose(false);
57+
}
58+
#endregion
59+
}
60+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
using System;
2+
using System.Threading;
3+
using System.Threading.Tasks;
4+
5+
namespace THNETII.Common.Threading
6+
{
7+
public static class SemaphoreSlimExtensions
8+
{
9+
public static SemaphoreSlimContext WaitContext(this SemaphoreSlim semaphore)
10+
{
11+
if (semaphore is null)
12+
throw new ArgumentNullException(nameof(semaphore));
13+
semaphore.Wait();
14+
return SemaphoreSlimContext.CreateNoVerify(semaphore);
15+
}
16+
17+
public static SemaphoreSlimContext WaitContext(this SemaphoreSlim semaphore,
18+
int millisecondsTimeout)
19+
{
20+
if (semaphore is null)
21+
throw new ArgumentNullException(nameof(semaphore));
22+
var entered = semaphore.Wait(millisecondsTimeout);
23+
return entered ? SemaphoreSlimContext.CreateNoVerify(semaphore) : null;
24+
}
25+
26+
public static SemaphoreSlimContext WaitContext(this SemaphoreSlim semaphore,
27+
TimeSpan timeout)
28+
{
29+
if (semaphore is null)
30+
throw new ArgumentNullException(nameof(semaphore));
31+
var entered = semaphore.Wait(timeout);
32+
return entered ? SemaphoreSlimContext.CreateNoVerify(semaphore) : null;
33+
}
34+
35+
public static SemaphoreSlimContext WaitContext(this SemaphoreSlim semaphore,
36+
CancellationToken cancelToken)
37+
{
38+
if (semaphore is null)
39+
throw new ArgumentNullException(nameof(semaphore));
40+
semaphore.Wait(cancelToken);
41+
return SemaphoreSlimContext.CreateNoVerify(semaphore);
42+
}
43+
44+
public static SemaphoreSlimContext WaitContext(this SemaphoreSlim semaphore,
45+
int millisecondsTimeout, CancellationToken cancelToken)
46+
{
47+
if (semaphore is null)
48+
throw new ArgumentNullException(nameof(semaphore));
49+
var entered = semaphore.Wait(millisecondsTimeout, cancelToken);
50+
return entered ? SemaphoreSlimContext.CreateNoVerify(semaphore) : null;
51+
}
52+
53+
public static SemaphoreSlimContext WaitContext(this SemaphoreSlim semaphore,
54+
TimeSpan timeout, CancellationToken cancelToken)
55+
{
56+
if (semaphore is null)
57+
throw new ArgumentNullException(nameof(semaphore));
58+
var entered = semaphore.Wait(timeout, cancelToken);
59+
return entered ? SemaphoreSlimContext.CreateNoVerify(semaphore) : null;
60+
}
61+
62+
public static async Task<SemaphoreSlimContext> WaitContextAsync(this SemaphoreSlim semaphore)
63+
{
64+
if (semaphore is null)
65+
throw new ArgumentNullException(nameof(semaphore));
66+
await semaphore.WaitAsync()
67+
.ConfigureAwait(continueOnCapturedContext: false);
68+
return SemaphoreSlimContext.CreateNoVerify(semaphore);
69+
}
70+
71+
public static async Task<SemaphoreSlimContext> WaitContextAsync(this SemaphoreSlim semaphore,
72+
int millisecondsTimeout)
73+
{
74+
if (semaphore is null)
75+
throw new ArgumentNullException(nameof(semaphore));
76+
var entered = await semaphore.WaitAsync(millisecondsTimeout)
77+
.ConfigureAwait(continueOnCapturedContext: false);
78+
return entered ? SemaphoreSlimContext.CreateNoVerify(semaphore) : null;
79+
}
80+
81+
public static async Task<SemaphoreSlimContext> WaitContextAsync(this SemaphoreSlim semaphore,
82+
TimeSpan timeout)
83+
{
84+
if (semaphore is null)
85+
throw new ArgumentNullException(nameof(semaphore));
86+
var entered = await semaphore.WaitAsync(timeout)
87+
.ConfigureAwait(continueOnCapturedContext: false);
88+
return entered ? SemaphoreSlimContext.CreateNoVerify(semaphore) : null;
89+
}
90+
91+
public static async Task<SemaphoreSlimContext> WaitContextAsync(this SemaphoreSlim semaphore,
92+
CancellationToken cancelToken)
93+
{
94+
if (semaphore is null)
95+
throw new ArgumentNullException(nameof(semaphore));
96+
await semaphore.WaitAsync(cancelToken)
97+
.ConfigureAwait(continueOnCapturedContext: false);
98+
return SemaphoreSlimContext.CreateNoVerify(semaphore);
99+
}
100+
101+
public static async Task<SemaphoreSlimContext> WaitContextAsync(this SemaphoreSlim semaphore,
102+
int millisecondsTimeout, CancellationToken cancelToken)
103+
{
104+
if (semaphore is null)
105+
throw new ArgumentNullException(nameof(semaphore));
106+
var entered = await semaphore.WaitAsync(millisecondsTimeout, cancelToken)
107+
.ConfigureAwait(continueOnCapturedContext: false);
108+
return entered ? SemaphoreSlimContext.CreateNoVerify(semaphore) : null;
109+
}
110+
111+
public static async Task<SemaphoreSlimContext> WaitContextAsync(this SemaphoreSlim semaphore,
112+
TimeSpan timeout, CancellationToken cancelToken)
113+
{
114+
if (semaphore is null)
115+
throw new ArgumentNullException(nameof(semaphore));
116+
var entered = await semaphore.WaitAsync(timeout, cancelToken)
117+
.ConfigureAwait(continueOnCapturedContext: false);
118+
return entered ? SemaphoreSlimContext.CreateNoVerify(semaphore) : null;
119+
}
120+
}
121+
}

0 commit comments

Comments
 (0)