相关疑难解决方法(0)

锁定一个实习的字符串?

更新:如果这个方法不是线程安全的,这是可以接受的,但我有兴趣学习如何使它保持线程安全.另外,key如果我可以避免它,我不想锁定所有值的单个对象.

原始问题:假设我想编写一个带有键和函数的高阶函数,并检查对象是否已使用给定的密钥进行高速缓存.如果是,则返回缓存的值.否则,运行给定的函数并缓存并返回结果.

这是我的代码的简化版本:

public static T CheckCache<T>(string key, Func<T> fn, DateTime expires)
{
    object cache = HttpContext.Current.Cache.Get(key);
    //clearly not thread safe, two threads could both evaluate the below condition as true
    //what can I lock on since the value of "key" may not be known at compile time?
    if (cache == null)
    {
        T result = fn();
        HttpContext.Current.Cache.Insert(key, result, null, expires, Cache.NoSlidingExpiration);
        return result;
    }
    else
        return (T)cache;
}
Run Code Online (Sandbox Code Playgroud)

另外,假设我key在编译时不知道所有可能的值.

如何使这个线程安全?我知道我需要在这里引入锁定,以防止1+线程将我的条件评估为真,但我不知道要锁定什么.我读过的许多关于锁定的例子(例如Jon Skeet的文章)建议使用仅用于锁定的"虚拟"私有变量.在这种情况下,这是不可能的,因为密钥在编译时是未知的.我知道我可以通过为每个人使用相同的锁来轻松地使这个线程安全 …

c# locking thread-safety higher-order-functions

17
推荐指数
2
解决办法
4537
查看次数

如何在.NET ConcurrentDictionary中实现remove_if功能

我有一个场景,我必须保持引用计数对象的给定键ConcurrentDictionary,如果引用计数达到0,我想删除键.这必须是线程安全的,因此我打算使用ConcurrentDictionary.

示例程序如下.在并发字典中,我有键和值,值是KeyValuePair,它保存我的自定义对象和引用计数.

ConcurrentDictionary<string, KeyValuePair<object, int>> ccd = 
    new ConcurrentDictionary<string, KeyValuePair<object, int>>();

// following code adds the key, if not exists with reference 
// count   for  my custom object to 1
// if the key already exists it increments the reference count

var addOrUpdateValue = ccd.AddOrUpdate("mykey",
    new KeyValuePair<object, int>(new object(), 1),
    (k, pair) => new KeyValuePair<object, int>(pair.Key, pair.Value + 1));
Run Code Online (Sandbox Code Playgroud)

现在我想要一种方法来在引用计数达到0时删除密钥.我在想,删除带有ConcurrentDictionary键和谓词的方法,如果谓词返回'true'则删除密钥.例.

ConcurrentDictionary.remove(TKey, Predicate<TValue> ). 
Run Code Online (Sandbox Code Playgroud)

没有这样的方法ConcurrentDictionary,问题是如何以线程安全的方式做同样的事情?

.net c# multithreading task-parallel-library concurrentdictionary

11
推荐指数
2
解决办法
667
查看次数

C#这个方法线程安全吗?

请考虑以下代码:

Dictionary<string, string> list = new Dictionary<string, string>();
object lockObj = new object();

public void MyMethod(string a) {

    if (list.Contains(a))
        return;

    lock (lockObj) {
        list.Add(a,"someothervalue");
    }
}
Run Code Online (Sandbox Code Playgroud)

假设我MyMethod("mystring")同时从不同的线程调用.

是否可能有多个线程(我们只需将其作为两个)同时输入if (!list.Contains(a))语句(具有几个CPU周期差异),两个线程都被评估为false,一个线程进入关键区域而另一个线程进入关键区域被锁定在外面,所以第二个线程进入并"mystring"在第一个线程退出后再次添加到列表中,导致字典尝试添加重复键?

c# multithreading

8
推荐指数
2
解决办法
557
查看次数

这对于并发集/队列组合看起来是一种合理的方法吗?

更新:正如Brian指出的那样,我最初的想法确实存在并发问题.这个ConcurrentDictionary<TKey, TValue>.AddOrUpdate方法的签名有点模糊,可以让一个懒惰的思想家(比如我自己)相信所有东西 - 集合添加以及队列推送 - 会以某种方式同时发生,原子地(即,神奇地) ).

回想起来,有这种期望对我来说是愚蠢的.实际上,无论执行情况如何AddOrUpdate,都应该很清楚,我的原始想法中仍会存在竞争条件,正如Brian所指出的那样:在添加到集合之前推送到队列,因此可能发生以下事件序列:

  1. 项目被推送到队列
  2. 项目从队列中弹出
  3. 项目(未)从集合中删除
  4. 项目已添加到设置中

上述序列将导致集合中的项目不在队列中,从而有效地将该项目列入数据结构的黑名单.

现在,我想了一会儿,我开始认为以下方法可以解决这些问题:

public bool Enqueue(T item)
{
    // This should:
    // 1. return true only when the item is first added to the set
    // 2. subsequently return false as long as the item is in the set;
    //    and it will not be removed until after it's popped
    if (_set.TryAdd(item, true))
    {
        _queue.Enqueue(item);
        return true;
    }

    return false;
}
Run Code Online (Sandbox Code Playgroud)

以这种方式构造它, …

.net queue concurrency multithreading set

4
推荐指数
1
解决办法
918
查看次数

对 ConcurrentDictionary 的线程安全更改

ConcurrentDictionary我正在循环中填充 a Parallel.ForEach

var result = new ConcurrentDictionary<int, ItemCollection>();

Parallel.ForEach(allRoutes, route => 
{
    // Some heavy operations

    lock(result)
    {
        if (!result.ContainsKey(someKey))
        {
            result[someKey] = new ItemCollection();
        }

        result[someKey].Add(newItem);
    }
}
Run Code Online (Sandbox Code Playgroud)

如何在不使用 lock 语句的情况下以线程安全的方式执行最后的步骤?

编辑: 假设这ItemCollection是线程安全的。

c# parallel-processing task-parallel-library concurrentdictionary parallel.foreach

2
推荐指数
1
解决办法
373
查看次数