问题描述
因此,对于一项分配,我们需要选择使用C#-Lock或使用自行实现的TaS-Lock.我读到的有关TaS-Locks的信息是,它使用1个原子步来读取和写入值.建议我们为此使用C#中的Interlocked类.
So for an assignment we need to have the option to either use the C#-Lock or use a self-implemented TaS-Lock. What I've read about TaS-Locks is that it uses 1 atomic step to both read and write a value. It was suggested to us that we use the Interlocked class in C# for this.
到目前为止,这是我所拥有的,但似乎导致答案不一致:
So far this is what I've got, but it seems to result in inconsistent answers:
public interface Lock
{
void Lock();
void Unlock();
}
public class C_Sharp_Lock : Lock
{
readonly Object myLock = new object();
public void Lock()
{
Monitor.Enter(myLock);
}
public void Unlock()
{
Monitor.Exit(myLock);
}
}
public class Tas_Lock : Lock
{
int L = 0;
public void Lock()
{
while (0 == Interlocked.Exchange(ref L, 1)) { };
}
public void Unlock()
{
Interlocked.Exchange(ref L, 0);
}
}
有人知道我在做什么错吗?
Does anyone know what I'm doing wrong here?
编辑:作为对Kevin的回复:
Edit: As a response to Kevin:
我将其更改为以下内容:
I've changed it to the following:
public class Tas_Lock : Lock
{
int L = 0;
public void Lock()
{
while (0 == Interlocked.CompareExchange(ref L, 1, 0)) { };
}
public void Unlock()
{
Interlocked.Exchange(ref L, 0);
}
}
但是这仍然返回不一致的结果.
However this still returns inconsistent results.
编辑#2:更改为C#锁定:
public class C_Sharp_Lock : Lock
{
readonly Object myLock = new object();
bool lockTaken = false;
public void Lock()
{
Monitor.Enter(myLock, ref lockTaken);
}
public void Unlock()
{
if (lockTaken)
Monitor.Exit(myLock);
}
}
推荐答案
您误解了 Interlocked.CompareExchange
的工作方式.如果它先前等于提供的比较符,则原子交换一个值,并返回先前的值.
You're misunderstanding the way Interlocked.CompareExchange
works. It swaps atomatically a value if it's previously equal to the provided comparand, and returns the previous value.
简而言之, Interlocked.CompareExchange(ref L,1,0)
将:
- 检查L是否等于0
- 如果L等于0,则它将L设置为1并返回上一个值(0)
- 如果L不等于0(因此等于1),则它将返回前一个值(1)
从那里开始,您应该做的是循环直到 Interlocked.CompareExchange
返回0(这意味着已获得锁).在您的代码中,您正在等待 Interlocked.CompareExchange
返回0.
From there, what you should do is loop until Interlocked.CompareExchange
returns 0 (which means that the lock was acquired). In your code, you're waiting while Interlocked.CompareExchange
returns 0.
固定代码:
public class Tas_Lock
{
int L = 0;
public void Lock()
{
while (0 != Interlocked.CompareExchange(ref L, 1, 0)) { }
}
public void Unlock()
{
Interlocked.Exchange(ref L, 0);
}
}
需要注意的两件事:
-
Unlock
中的Interlocked.Exchange
可以替换为更快的Volatile.Write
(甚至可以说是简单的写法) - 如果不是要分配的,则可以使用内置类
SpinLock
,该类已经以优化的方式完成了所有这些工作
- The
Interlocked.Exchange
inUnlock
could be replaced by a fasterVolatile.Write
(or even, though arguable, a simple write) - If it wasn't for an assignment, you could use the built-in class
SpinLock
, which already does all that stuff in an optimized way
这篇关于如何在C#中实现自己的TaS-Lock?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!