我有一个C#的情况,我有一个简单类型的列表.可以通过多个线程访问此列表:可以添加或删除条目,并且可以检查条目是否存在.我已将列表封装在一个对象中,这个对象到目前为止只暴露了这三个操作.
我有几个案例要处理(与我刚才提到的方法不完全相同).
整个想法是条目的存在表示锁定.如果存在条目,则无法更改其标识的对象,并且代码无法继续,因为它正在其他位置进行修改.
这些看似简单的新手情况,但我在并发问题上让自己感到高兴,这让我有点偏执,而且我也不熟悉C#的并发机制.
处理这个问题的最佳方法是什么?我完全没了?应该检查并添加(测试和设置?)组合成第四个原子操作?我只是将锁块添加到访问列表的方法中吗?
此外,是否有可能对这种事情进行单元测试(不是简单的操作,并发情况)?
单元测试肯定会很难.
这可以通过.NET中的"本机"并发机制合理地完成:锁定语句和Monitor.Wait/ Monitor.PulseAll.除非你的每个项目都有一个单独的监视器,否则你需要在删除任何东西时唤醒所有线程 - 否则你将无法告诉"正确"的线程唤醒.
如果它实际上只是一组项目,那么您可能希望使用HashSet<T>而不是List<T>代表集合,顺便说一句 - 您提到的任何内容都与订购无关.
示例代码,假设一个集合适合您:
using System;
using System.Collections.Generic;
using System.Threading;
public class LockCollection<T>
{
private readonly HashSet<T> items = new HashSet<T>();
private readonly object padlock = new object();
public bool Contains(T item)
{
lock (padlock)
{
return items.Contains(item);
}
}
public bool Add(T item)
{
lock (padlock)
{
// HashSet<T>.Add does what you want already :)
// Note that it will return true if the item
// *was* added (i.e. !Contains(item))
return items.Add(item);
}
}
public void WaitForNonExistence(T item)
{
lock (padlock)
{
while (items.Contains(item))
{
Monitor.Wait(padlock);
}
}
}
public void WaitForAndAdd(T item)
{
lock (padlock)
{
WaitForNonExistence(item);
items.Add(item);
}
}
public void Remove(T item)
{
lock (padlock)
{
if (items.Remove(item))
{
Monitor.PulseAll(padlock);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
(诚然,未完全未经测试.您可能还想为等待代码指定超时...)
虽然#1可能是最简单的写入,但它本质上是一种无用的方法.除非在完成"条目存在"的查询后持有相同的锁,否则实际上返回"在过去的某个时刻存在条目".它不会提供有关当前条目存在的任何信息.
在发现列表中的值然后执行任何操作以检索,删除值之间,另一个线程可能会为您删除它.
并发列表中包含的操作应该与您计划在该检查的真/假存在的情况下执行的操作相结合.例如TestAdd()或TestRemove()是多少安全比包含+添加或包含+删除
| 归档时间: |
|
| 查看次数: |
14016 次 |
| 最近记录: |