【问题标题】:Threadsafety and foreach with static readonly arrays带有静态只读数组的线程安全和 foreach
【发布时间】:2016-11-24 02:10:04
【问题描述】:

我有几个定义为“静态只读”的 char[] 和 string[] 类型的数组。他们的项目永远不会改变。

'foreach' 和 'generics' 枚举是线程安全的吗?

private static readonly string[] staticReadOnlyArray = new string[] { "someKey0", "someKey1", "someKey2", ... };

public bool SomeThreadSharedCall(string toCheck)
{
    // #1
    foreach (string s in staticReadOnlyArray)
    {
        if (s == toCheck)
            return true;
    }
    return false;

    // #2
    return staticReadOnlyArray.Contains(toCheck);

    // or #3
    return staticReadOnlyArray.Any(s => string.Compare(toCheck, s, StringComparison.OrdinalIgnoreCase) == 0);

    // or #4
    staticReadOnlyArray.ForEach(s => someAction(s, toCheck));
}

【问题讨论】:

    标签: c# foreach static thread-safety readonly


    【解决方案1】:

    您的方法中的操作是“线程安全的”,仅基于您声称 Their items never change.;但是,给定代码中的任何内容都不能保证这一点。

    术语threadsafe 通常用于表示有问题的代码保证数据不会改变,或者如果它可以改变,操作将仍然会产生正确的结果。

    您需要执行your own synchronization logic 以使代码真正线程安全。

    === 回答你的 cmets:

    GetEnumerator() 的返回值——你所调用的iterator——本身对于调用线程来说是安全的,但这不是这里的问题。它是底层集合(数组),它不是线程安全的,因为它可以改变。

    foreach 更改为for 循环不会使代码更加线程安全。您需要同步对集合的访问,或者使其不可变。

    在您的情况下,我建议后者,因为您的数组中的数据是恒定的。为了让您具体了解,这里有一些概念性代码:

    private static readonly IEnumerable<string> staticReadOnlyData = Array.AsReadOnly( new string[] { "someKey0", "someKey1", "someKey2", ... } );
    
    public bool SomeThreadSharedCall(string toCheck)
    {
        // #1
        foreach (string s in staticReadOnlyData)
        {
            if (s == toCheck)
                return true;
        }
        return false;
    
        // #2
        return staticReadOnlyData.Contains(toCheck);
    
        // or #3
        return staticReadOnlyData.Any(s => string.Compare(toCheck, s, StringComparison.OrdinalIgnoreCase) == 0);
    }
    

    【讨论】:

    • 感谢您的回复。我清楚地了解 C++ 上的 Win32 API 多线程。但我对 C# 4 感到困惑。该数组是 IEnumerable。对于移动,它使用 IEnumerator iterator = array.GetEnumerator() 的引用。那么,迭代器是在引用 IEnumerator 的新副本,还是每个线程都获得对迭代器对象的一个​​副本的引用?在最后一种情况下,我们遇到了问题。
    • 我需要的只是一个常量预定义数组和用于查找的线程安全方法。我有一个难题 - 是否将代码从 foreach 重写为 for(int i = 0; i &lt; array.Count; i++)
    【解决方案2】:

    如果您不确定,最好的方法是测试它!但是,是的,它们是线程安全的。

    【讨论】:

      猜你喜欢
      • 2011-01-22
      • 2012-08-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-16
      相关资源
      最近更新 更多