使用 volatile 关键字和 lock 语句

发布于 2024-12-15 20:44:37 字数 456 浏览 1 评论 0原文

我在应用程序中收到“对易失性字段的引用不会被视为易失性”警告。我明白为什么。

作为一个简单的例子,即使我仍然收到警告,下面的代码是否会使问题线程安全?

private volatile int myVal = 10;
private int myNonVolatileNumber = 50;
private static readonly object lockObject = new object();

private void ChangeValue(ref int Value)
{
  lock (lockObject)
  {
    Value = 0;
  }
}

private void MyMethod()
{
  ChangeValue(ref myVal); //Warning here
  ChangeValue(ref myNonVolatileNumber); //no warning
}

I am getting the "a reference to a volatile field will not be treated as volatile" warning in an application. I understand why.

As a simple example will the below code make the issue thread safe even though I will get the warning still?

private volatile int myVal = 10;
private int myNonVolatileNumber = 50;
private static readonly object lockObject = new object();

private void ChangeValue(ref int Value)
{
  lock (lockObject)
  {
    Value = 0;
  }
}

private void MyMethod()
{
  ChangeValue(ref myVal); //Warning here
  ChangeValue(ref myNonVolatileNumber); //no warning
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

温柔戏命师 2024-12-22 20:44:37

锁定会强制两侧的内存屏障,所以是的,您的示例是线程安全的。

Locking forces memory barriers on both sides, so yes, your example is thread safe.

从来不烧饼 2024-12-22 20:44:37

您几乎自己回答:

ChangeValue(ref myVal); //Warning here
ChangeValue(ref myNonVolatileNumber); //no warning

编译后的 ChangeValue() 只有 1 个副本,其中的代码应该实现“易失性”行为。但编译器(Jitter)在编译时无法预测所有调用。唯一的选择是将每个 ref 参数视为易失性的,这将是非常低效的。

但请参阅@Steven 的评论,易失性 毫无用处,应该避免。

You almost answer it yourself:

ChangeValue(ref myVal); //Warning here
ChangeValue(ref myNonVolatileNumber); //no warning

There is only 1 copy of the compiled ChangeValue(), the code inside should implement the 'volatile' behaviour. But the compiler (Jitter) cannot predict all calls when it compiles. The only option would be to treat every ref parameter as volatile, that would be very inefficient.

But see @Steven's comment, volatile is as good as useless and should be avoided.

穿透光 2024-12-22 20:44:37

可能在您使用过的地方不需要使用 volatile 关键字。

这个问题回答了所有应该使用 volatile 关键字的地方:

什么时候应该在 C# 中使用 volatile 关键字?

Probably there is no need for the usage of the volatile keyword at the place you have used.

This SO Question answers where all should the volatile keyword should be used if at all:

When should the volatile keyword be used in C#?

动次打次papapa 2024-12-22 20:44:37

会有什么问题

private int val = 10;
private var valLock = new object();
private int nonVolatileNumber = 50;
private var nonVolatileNumberLock = new object();

public int Value
{
    get { lock(valLock) return val; }
    set { lock(valLock) val = value; }
}

public int NonVolatileNumber
{
    get { lock(nonVolatileNumberLock) return nonVolatileNumber; }
    set { lock(nonVolatileNumberLock) nonVolatileNumber = value; }
}

,这里唯一的风险是后续代码访问该属性的私有成员。

对于 32 位整数,甚至 64 位系统上的 64 位整数,由于读取是原子的,因此您可以使用 Interlocked 像这样的类...

private int val = 10;

public int Value
{
    get { return val; }
    set { Interlocked.Exchange(ref val, value); }
}

或者在更复杂的类型的情况下,您可以使用 ReadWriterLockSlim ...

private SomeStructure complex;
private var complexLock = new ReadWriterLockSlim();

public SomeStructure Complex
{
    get
    {
        complexLock.EnterReadLock();
        try
        {
            return complex;
        }
        finally
        {
            complexLock.ExitReadlock();
        }
    }
    set
    {
        complexLock.EnterWriteLock();
        try
        {
            return complex;
        }
        finally
        {
            complexLock.ExitWritelock();
        }
    }
}

这比标准锁更好,因为它允许多个同时读取。

What would be wrong with

private int val = 10;
private var valLock = new object();
private int nonVolatileNumber = 50;
private var nonVolatileNumberLock = new object();

public int Value
{
    get { lock(valLock) return val; }
    set { lock(valLock) val = value; }
}

public int NonVolatileNumber
{
    get { lock(nonVolatileNumberLock) return nonVolatileNumber; }
    set { lock(nonVolatileNumberLock) nonVolatileNumber = value; }
}

, the only risk here is that subsequent code accesses the property's private member.

In the case of 32bit integers, or even 64bit integers on a 64bit system, becasue the reads wil be atomic, you could use the Interlocked class like this ...

private int val = 10;

public int Value
{
    get { return val; }
    set { Interlocked.Exchange(ref val, value); }
}

Or in the case of a more complex type you could use ReadWriterLockSlim ...

private SomeStructure complex;
private var complexLock = new ReadWriterLockSlim();

public SomeStructure Complex
{
    get
    {
        complexLock.EnterReadLock();
        try
        {
            return complex;
        }
        finally
        {
            complexLock.ExitReadlock();
        }
    }
    set
    {
        complexLock.EnterWriteLock();
        try
        {
            return complex;
        }
        finally
        {
            complexLock.ExitWritelock();
        }
    }
}

This is better than a standard lock because it allows multiple simultaneous reads.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文