gpt4 book ai didi

c# - 只释放给后进线程的线程同步(加锁)

转载 作者:太空狗 更新时间:2023-10-29 23:37:55 25 4
gpt4 key购买 nike

确保只有“后入”线程可以访问互斥锁/锁定区域而中间线程不获取锁的正确方法是什么?

示例序列:

A acquires lock
B waits
C waits
B fails to acquire lock*
A releases lock
C acquires lock

*B 应该无法通过异常(如 SemaphoreSlim.Wait(CancellationToken) 或 bool 型 Monitor.TryEnter() 类型构造)获取锁。

我可以想到几个类似的方案来实现这一点(例如使用 CancellationTokenSourceSemaphoreSlim),但没有一个看起来特别优雅。

这种情况有通用的做法吗?

最佳答案

这应该可以像您希望的那样工作,它使用大小为 1 的 SemaphoreSlim 来控制它。我还添加了对传入 CancellationToken 以取消提前等待锁定的支持,它还支持 WaitAsync 返回任务而不是阻塞。

public sealed class LastInLocker : IDisposable
{
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1);
private CancellationTokenSource _cts = new CancellationTokenSource();
private bool _disposed = false;

public void Wait()
{
Wait(CancellationToken.None);
}

public void Wait(CancellationToken earlyCancellationToken)
{
if(_disposed)
throw new ObjectDisposedException("LastInLocker");

var token = ReplaceTokenSource(earlyCancellationToken);
_semaphore.Wait(token);
}

public Task WaitAsync()
{
return WaitAsync(CancellationToken.None);
}

public async Task WaitAsync(CancellationToken earlyCancellationToken)
{
if (_disposed)
throw new ObjectDisposedException("LastInLocker");

var token = ReplaceTokenSource(earlyCancellationToken);

//I await here because if ReplaceTokenSource thows a exception I want the
//observing of that exception to be deferred until the caller awaits my
//returned task.
await _semaphore.WaitAsync(token).ConfigureAwait(false);
}

public void Release()
{
if (_disposed)
throw new ObjectDisposedException("LastInLocker");

_semaphore.Release();
}

private CancellationToken ReplaceTokenSource(CancellationToken earlyCancellationToken)
{
var newSource = CancellationTokenSource.CreateLinkedTokenSource(earlyCancellationToken);
var oldSource = Interlocked.Exchange(ref _cts, newSource);
oldSource.Cancel();
oldSource.Dispose();

return newSource.Token;
}

public void Dispose()
{
_disposed = true;

_semaphore.Dispose();
_cts.Dispose();
}
}

这是一个重新创建测试示例的小测试程序

internal class Program
{
static LastInLocker locker = new LastInLocker();
private static void Main(string[] args)
{
Task.Run(() => Test("A"));
Thread.Sleep(500);
Task.Run(() => Test("B"));
Thread.Sleep(500);
Task.Run(() => Test("C"));
Console.ReadLine();
}

private static void Test(string name)
{
Console.WriteLine("{0} waits for lock", name);
try
{
locker.Wait();
Console.WriteLine("{0} acquires lock", name);

Thread.Sleep(4000);
locker.Release();

Console.WriteLine("{0} releases lock", name);
}
catch (Exception)
{
Console.WriteLine("{0} fails to acquire lock", name);
}
}
}

输出

A waits for lockA acquires lockB waits for lockC waits for lockB fails to acquire lockA releases lockC acquires lockC releases lock

关于c# - 只释放给后进线程的线程同步(加锁),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32361372/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com