使用C#示例锁定以使类线程安全,或者此类线程是否安全?

时间:2012-01-19 14:48:21

标签: c# locking thread-safety

我正在尝试调查锁定以创建线程安全类并且有几个问题。鉴于以下课程:

    public class StringMe 
    {
        protected ArrayList  _stringArrayList = new ArrayList();
        static readonly object _locker = new object();

        public void AddString(string stringToAdd)
        {
            lock (_locker) _stringArrayList.Add(stringToAdd);
        }

        public override string ToString()
        {
            lock (_locker)
            {
return string.Join(",",string[])_stringArrayList.ToArray(Type.GetType("System.String")));
            }
        }
    }

1)我是否成功制作了AddString和TMString threadsafe?

2)在我创建的ToString方法中是否需要锁定它以使其线程安全?

3)是否只需要修改需要锁定数据的方法,或者是否需要锁定读取和写入操作以使其线程安全?

非常感谢您的时间!

3 个答案:

答案 0 :(得分:13)

不,您没有使这些调用成为线程安全的 - 因为_stringArrayList字段受到保护。在调用AddStringToString时,子类可以随意执行任何操作。

例如(正如其他答案声称您的代码 线程安全。)

public class BadStringMe : StringMe
{
    public void FurtleWithList()
    {
        while (true)
        {
            _stringArrayList.Add("Eek!");
            _stringArrayList.Clear();
        }
    }
}

然后:

BadStringMe bad = new BadStringMe();
new Thread(bad.FurtleWithList).Start();
bad.AddString("This isn't thread-safe");

首选私有字段 - 这样可以更轻松地推理您的代码。

此外:

  • 这些天喜欢List<T>ArrayList
  • 由于某种原因你正在使用 static 变量锁定...所以即使你有几个StringMe个实例,只有一个线程可以在{{1}中} 总计
  • 使用AddStringtypeof(string)
  • 更清晰
  

3)是否只需要修改需要锁定数据的方法,或者是否需要锁定读取和写入操作以使其线程安全?

全部,假设可能有一些操作。如果所有只是读取,则不需要任何锁定 - 但是否则您的读取线程可以读取数据结构中的两位数据,这些数据在两者之间进行了修改,即使只有一个线程。 (还要考虑记忆模型的考虑因素。)

答案 1 :(得分:4)

  

1)我是否成功制作了AddString和TMString threadsafe?

是的,如果您将_stringArrayList更改为私人

  

2)在我创建的ToString方法中是否有必要锁定它以使其线程安全?

  

3)是否只需要修改需要锁定数据的方法,或者是否需要锁定读取和写入操作以使其线程安全?

读写。

答案 2 :(得分:3)

对所有三个都是肯定的(即读/写到最后一个)。

但还有更多:

您创建锁定对象static,而您保护的数据是每个实例字段。这意味着StringMe的所有实例都相互受到保护,尽管它们具有不同的数据(即_stringArrayList的实例)。对于您提供的示例,您可以从static中删除_locker修饰符。更确切地说,您通常为一组数据定义“锁定”,或者更好的不变量,您要保留。通常,锁的生命周期(和范围)应该等于数据的生命周期(和范围)。

另外,为了更好地衡量,您保护的数据的可见性不应高于锁定数据。在您的示例中,派生实现可以在不获取锁定的情况下更改_stringArrayList(因为它受到保护),从而破坏了不变量。我会同时使它们private,如果必须的话,只将_stringArrayList通过(正确锁定)方法暴露给派生类。