C# 这是一份清单<;T>;属性线程安全? private List\T; 私有只读对象_syncLock=新对象(); 私有列表MyT { 得到 { 锁(同步锁) return_T.ToList(); } 设置 { 锁(同步锁) _T=数值; } }

C# 这是一份清单<;T>;属性线程安全? private List\T; 私有只读对象_syncLock=新对象(); 私有列表MyT { 得到 { 锁(同步锁) return_T.ToList(); } 设置 { 锁(同步锁) _T=数值; } },c#,list,thread-safety,C#,List,Thread Safety,是。您使用了一个成员变量作为锁,并确保它不能更改。那很好。是的,你看起来很安全。如果查看ToList()的定义,它是: private List<T> _T; private readonly object _syncLock = new object(); private List<T> MyT { get { lock (_syncLock) re

是。您使用了一个成员变量作为锁,并确保它不能更改。那很好。

是的,你看起来很安全。如果查看ToList()的定义,它是:

    private List<T> _T;
    private readonly object _syncLock = new object();

    private List<T> MyT
    {
        get
        {
            lock (_syncLock)
                return _T.ToList<T>();
        }
        set
        {
            lock (_syncLock)
                _T = value;
        }
    }
公共静态列表列表(此IEnumerable源代码)
{
if(source==null)
{
抛出错误。ArgumentNull(“源”);
}
返回新列表(源);
}
因此,本质上,您正在创建一个新列表,其中包含旧列表的元素,所有这些元素都位于您提供的锁之下,从而使其具有线程安全性


现在,列表的内容将是两个列表中相同的引用,因此它不会保护您不更改列表中存储的原始对象,它只保护列表本身。

不,它不是线程安全的。请看以下代码:

public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source)
{
    if (source == null)
    {
        throw Error.ArgumentNull("source");
    }
    return new List<TSource>(source);
}
静态MyClass sharedInstance=。。。;
//创建一个列表
var list=新列表();
//共享列表
sharedInstance.MyT=列表;
//列表现在已共享,此调用不是线程安全的。
增加(5);
问题在于,您允许使用者引用内部数据结构。您可以按如下方式解决此问题:

static MyClass<int> sharedInstance = ...;

// Create a list
var list = new List<int>();

// Share the list
sharedInstance.MyT = list;

// list is now shared, this call is not thread-safe.
list.Add(5);
私有列表MyT
{
得到
{
锁(同步锁)
return_T.ToList();
}
设置
{
var copy=value.ToList();
锁(同步锁)
_T=复制;
}
}

Exact dupe:假设您不会根据当前值更新当前值。。。是的,它是线程安全的。但是,如果您有任何代码看起来像“myTSObj.MyT=myTSObj.MyT+1”,那么没有。。。真的不是。在这种情况下,您已经对竞争条件敞开了大门。我认为修改原始列表会修改ToList()制作的副本,而不是原始列表是安全的。这将被分配为新成员。然而,你仍然可以有比赛条件。具体如何?这是一个列表,不像你的其他评论中那样是一个int。是的,但想法还是一样的。假设您的逻辑将一个项目添加到列表中,如果该项目在列表中不存在。但是,运行相同逻辑的另一个线程执行相同的操作。有可能多次以相同的值结束。为了避免这种情况,你的逻辑应该是锁定对象,因为它不可能避免所有这样的情况;然而,我相信这不是一个特定于这种逻辑的竞争条件。相反,它是特定于使用类的。此逻辑使列表属性线程安全。竞态条件是使用code.True时的一个问题。我同意这一点,但问题是“这是线程安全的吗”,答案是否定的。它不可能是线程安全的,因为他没有定义需要线程安全的用例。如果用例是“我希望能够读取整个列表,并在不混淆其他类的情况下将值分配给新列表的引用”,那么是的。它是线程安全的。否则,它真的不是。没关系。我将其用于值类型。仅通过查看
ToList()
方法,无法得出线程安全的结论。事实上,当向这个方法提供一个实例时,在下面更改它会破坏它(查看List.ctor)。看看我的答案。这里我举一个例子来说明如何引入竞争条件。您需要锁定集合吗?因为这只是一个参考assignment@EpiX:严格来说不是。拥有锁的优点是它增加了一个内存屏障。这将清除缓存并防止其他线程获取旧的(已缓存的)引用。因此,即使在调用
set
之后,它也会阻止其他线程获取旧值。但是由于
get
中已经使用了
lock
,因此
set
中的
lock
是多余的。然而,我确实喜欢在set和get中使用lock,因为这在大多数情况下是必需的,并且使代码在这种情况下不那么混乱。如果我们要从
集合
中删除
,我们必须明确说明为什么不需要该
private List<T> MyT
{
    get
    {
        lock (_syncLock)
            return _T.ToList<T>();
    }
    set
    {
        var copy = value.ToList();

        lock (_syncLock)
            _T = copy;
    }
}