如何在c#中实现自己的任务锁定?

时间:2022-09-02 14:48:24

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.

因此,对于一个作业,我们需要选择使用c#锁或使用自实现的任务锁。我读到的关于任务锁的内容是,它使用1原子步骤来读取和写入一个值。有人建议我们在c#中使用互锁类。

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?

有人知道我做错了什么吗?

Edit: As a response to Kevin:

编辑:作为对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.

然而,这仍然返回不一致的结果。

Edit #2: Changes to C# lock:

编辑#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);
    }
}

1 个解决方案

#1


5  

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.

你误解了相互联系的方式。CompareExchange作品。如果先前的值与提供的比较值相等,它将自动交换一个值,并返回先前的值。

In short, Interlocked.CompareExchange(ref L, 1, 0) will:

简而言之,联锁。CompareExchange(ref L, 1,0)将:

  • Check whether L is equal to 0
  • 检查L是否等于0
  • If L is equal to 0, then it will set L to 1 and return the previous value (0)
  • 如果L等于0,那么它将把L设为1,并返回上一个值(0)
  • If L isn't equal to 0 (and therefore is equal to 1), then it will return the previous value (1)
  • 如果L不等于0(因此等于1),则返回先前的值(1)

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.

从这里开始,您应该做的是循环,直到互锁。CompareExchange返回0(这意味着锁被获取)。在您的代码中,您正在等待,同时进行互锁。CompareExchange返回0。

The fixed code:

固定的代码:

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);
    }
}

Two things to note:

两个注意事项:

  • The Interlocked.Exchange in Unlock could be replaced by a faster Volatile.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
  • 如果不是赋值,您可以使用内置的类SpinLock,它已经以优化的方式完成了所有的工作。

#1


5  

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.

你误解了相互联系的方式。CompareExchange作品。如果先前的值与提供的比较值相等,它将自动交换一个值,并返回先前的值。

In short, Interlocked.CompareExchange(ref L, 1, 0) will:

简而言之,联锁。CompareExchange(ref L, 1,0)将:

  • Check whether L is equal to 0
  • 检查L是否等于0
  • If L is equal to 0, then it will set L to 1 and return the previous value (0)
  • 如果L等于0,那么它将把L设为1,并返回上一个值(0)
  • If L isn't equal to 0 (and therefore is equal to 1), then it will return the previous value (1)
  • 如果L不等于0(因此等于1),则返回先前的值(1)

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.

从这里开始,您应该做的是循环,直到互锁。CompareExchange返回0(这意味着锁被获取)。在您的代码中,您正在等待,同时进行互锁。CompareExchange返回0。

The fixed code:

固定的代码:

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);
    }
}

Two things to note:

两个注意事项:

  • The Interlocked.Exchange in Unlock could be replaced by a faster Volatile.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
  • 如果不是赋值,您可以使用内置的类SpinLock,它已经以优化的方式完成了所有的工作。