对C#中的同步集合进行非锁定访问的行为

问题描述 投票:0回答:1

我有一个私有集合(例如ISet<int>),可以通过多个线程进行访问或修改。

我有这样的逻辑,即该线程仅需要在某些状态下使ISet发生变化,而其他线程始终需要对其进行突变。另一个线程将始终使用lock,并在lock上实现了ISet关键字,如下所示:

lock (this._set)
{
    // some mutating operation on this._set
}

对于此线程,如果ISet包含一个称为intcurrentValue,则仅需要执行使该线程变异的操作,这种情况很少见。其他线程中的操作很频繁。因此,问题是我是否可以在获取ISet之前检查currentValue是否包含lock,以最小化此线程阻塞另一个线程的时间,如下所示:

if (this._set.Contains(currentValue))
{
    lock (this._set)
    {
            if (this._set.Contains(currentValue))
            {
                // some mutating operation on this._set
            }
    }
}

问题是lock外部的检查行为是否未定义,或者是否可能导致ISet处于未定义或意外状态。当然,返回的实际值不能被信任使用,这就是为什么要在lock中再次检查它的原因,但这是我可以期望的有效优化,还是会弄乱集合的某些内部状态?目标是尽可能少地使该线程中的lock

c# multithreading thread-safety locking task-parallel-library
1个回答
0
投票

仅读取集合值将不会引发异常或更改集合的值(如果这是您的意思)。它可能会返回脏数据,但是您已经声明希望这种可能性。我相信,从这样的非线程安全集合中读取数据甚至可以为您提供不完整的数据,或者是处于半旧状态,半新状态的数据(请参阅对C# multi-threading: Acquire read lock necessary?的响应>

让我们假设对_set.Contains(currentValue)的第一个测试返回true,并且另一个线程在删除currentValue之后立即更新集合。然后,您输入锁,但是现在当您测试_set.Contains(currentValue)时,它将返回false。

问题是,此线程对集合进行变异有多重要?您的代码每次都可能会丢失对集合进行变异的机会。您的优化可能最终产生相反的效果-通过不必要的锁定来减慢代码速度。

很难在不知道其他要求的情况下为您提供一个很好的选择,但是我想我已经回答了您的问题,并表明代码实际上根本没有优化,但是它本身不会破坏任何内容。

© www.soinside.com 2019 - 2024. All rights reserved.