因此,我在使用UWP应用程序时经常使用的一种模式是使用
SemaphoreSlim
实例以避免竞争条件(我不喜欢使用
lock
因为它需要一个额外的目标对象,并且不会异步锁定)。
典型的代码片段如下所示:
private readonly SemaphoreSlim Semaphore = new SemaphoreSlim(1);
public async Task FooAsync()
{
await Semaphore.WaitAsync();
// Do stuff here
Semaphore.Release();
}
附加的
try/finally
如果介于两者之间的代码可能会崩溃,我会阻止整个过程,但我希望保持信号量正常工作。
为了简化样板,我尝试编写一个具有相同行为的包装器类(包括
尝试/最终
位),所需代码更少。我也不想用
delegate
,因为这样每次都会创建一个对象,我只是想减少代码,而不改变它的工作方式。
我想出了这个类(为了简洁起见,删除了注释):
public sealed class AsyncMutex
{
private readonly SemaphoreSlim Semaphore = new SemaphoreSlim(1);
public async Task<IDisposable> Lock()
{
await Semaphore.WaitAsync().ConfigureAwait(false);
return new _Lock(Semaphore);
}
private sealed class _Lock : IDisposable
{
private readonly SemaphoreSlim Semaphore;
public _Lock(SemaphoreSlim semaphore) => Semaphore = semaphore;
void IDisposable.Dispose() => Semaphore.Release();
}
}
它的工作方式是,通过使用它,您只需要以下内容:
private readonly AsyncMutex Mutex = new AsyncMutex();
public async Task FooAsync()
{
using (_ = await Mutex.Lock())
{
// Do stuff here
}
}
短一行,带
尝试/最终
内置的(
using
方块),真棒。
现在,我不知道为什么会这样,尽管discard操作符
习惯于
那次丢弃实际上只是出于好奇,因为我知道我应该写
var _
,因为我需要它
IDisposable
要在
使用
阻止,而不是丢弃器。
但是,令我惊讶的是,这两种方法生成的IL相同:
.method public hidebysig instance void T1() cil managed
{
.maxstack 1
.locals init (
[0] class System.Threading.Tasks.AsyncMutex mutex,
[1] class System.IDisposable V_1
)
IL_0001: newobj instance void System.Threading.Tasks.AsyncMutex::.ctor()
IL_0006: stloc.0 // mutex
IL_0007: ldloc.0 // mutex
IL_0008: callvirt instance class System.Threading.Tasks.Task`1<class System.IDisposable> System.Threading.Tasks.AsyncMutex::Lock()
IL_000d: callvirt instance !0/*class System.IDisposable*/ class System.Threading.Tasks.Task`1<class System.IDisposable>::get_Result()
IL_0012: stloc.1 // V_1
.try
{
// Do stuff here..
IL_0025: leave.s IL_0032
}
finally
{
IL_0027: ldloc.1 // V_1
IL_0028: brfalse.s IL_0031
IL_002a: ldloc.1 // V_1
IL_002b: callvirt instance void System.IDisposable::Dispose()
IL_0031: endfinally
}
IL_0032: ret
}
“丢弃者”
IDisposable可识别
存储在字段中
V_1
并正确处理。
那么,为什么会发生这种情况?这个
docs
不要说discard操作符与
使用
块,他们只是说放弃分配被完全忽略。
谢谢