c#中的条件线程锁



当底层条件不恒定时,有可能有条件线程锁吗?

我有两个函数A和B,以及一个决定执行哪个函数的条件。A本身是线程安全的,对A的多个调用可以同时执行,B不是,并且是同步的。但是在执行B的过程中,条件可以改变(从false变为true),因此所有执行A的线程都会抛出错误。

if (condition)
{
A();
}
else
{
B();
}
A - thread safe
B - Synchronized using [MethodImpl(MethodImplOptions.Synchronized)]

因此,我正在寻找一种方法来锁定a,但只有当B正在运行时。请建议一种方法来实现这一点。

一些详述:我正在创建一个缓存,性能非常重要,因此毛毯锁是不可行的。

条件是指请求的数据是否存在于缓存中。

A() = AddToUpdates() -在缓存命中时执行,只是使用并发字典增加特定缓存键的更新次数。

B() = ProccessUpdates()和EvictLeastPriorityEntry() -在缓存丢失时执行,所有先前的更新将被处理,并且存储缓存项顺序的底层数据结构将被重新排列。

优先级最低的条目将被删除。

正如在公认的答案中提到的那样,ReaderWriterLock似乎是可行的方法。

只有一个问题,假设,thread1开始执行并且发生缓存命中,(在具有最低优先级的条目上)意味着if条件为真并进入if块。但是在调用A()之前,控制权被切换到thread2。

thread2 -缓存丢失,执行重新排序和删除(线程A()需要访问的条目)

现在当受控线程返回到thread1时,会出现错误。

这是我觉得应该工作的解决方案:

_lock.EnterReadLock();
if (condition)
{
A();
}
_lock.ExitReadLock();
if (!condition)
{
B();
}
void A()
{
// ....
}
void B()
{
_lock.EnterWriteLock();
// ...
_lock.ExitWriteLock();
}

这能行吗?

谢谢。

我可能解决你的问题可能是ReaderWriterLockSlim类。这是一个同步原语,允许多个并发的读操作,或者一个独占的写操作,但不能同时进行。

使用ReaderWriterLockSlim保护由多个线程读取且由一个线程一次写入的资源。ReaderWriterLockSlim允许多个线程处于读模式,允许一个线程处于写模式并独占锁的所有权,并允许一个具有读访问权限的线程处于可升级读模式,从可升级读模式中,线程可以升级到写模式而不必放弃对资源的读访问权限。

的例子:

private readonly ReaderWriterLockSlim _lock = new();
void A()
{
_lock.EnterReadLock();
try
{
//...
}
finally { _lock.ExitReadLock(); }
}
void B()
{
_lock.EnterWriteLock();
try
{
//...
}
finally { _lock.ExitWriteLock(); }
}

你的问题看起来很像这样:

  • A()是某种只读方法,所以线程安全。A的不同并行执行是可以的。

  • B()就像编写/改变A方法使用的东西。因此,如果A()同时执行,它就不是线程安全的。

例如,B()可以在List中写入,而a()可以在这个List中读取。你会得到异常InvalidOperationException: Collection Was modified;从A()抛出。

我建议你查找"生产者/消费者问题";在Google上查找大量的例子。

但是如果你绝对想开始B的执行,而A的执行已经/还没有结束,你可以使用Monitor类在A()中添加检查点,它用于锁定资源并与其他线程同步。但它更复杂,我将首先查看生产者/消费者模式,看看它是否满足需求

更多内容:

  • 我会检查是否使用了BlockingCollection类,也可以满足您的确切需求(并且易于使用)

  • MethodImplOptions的使用。Synchronized不建议使用,因为它使用公共锁。我们通常使用私有锁(object readonly _lock = new object();),所以除了这个对象的维护者之外没有人可以锁定它,从而防止死锁(并防止其他人指责你的代码有bug,因为其他人锁定了你的类实例,而不知道你在内部做了同样的事情)

最新更新