使用C#示例锁定以使类线程安全,还是该类线程安全?

使用C#示例锁定以使类线程安全,还是该类线程安全?,c#,locking,thread-safety,C#,Locking,Thread Safety,我正在尝试研究锁定以创建一个threadsafe类,并有几个问题。鉴于以下类别: public class StringMe { protected ArrayList _stringArrayList = new ArrayList(); static readonly object _locker = new object(); public void AddString(string stringToAdd)

我正在尝试研究锁定以创建一个threadsafe类,并有几个问题。鉴于以下类别:

    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和ToString线程安全

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

3) 是只修改需要锁定的数据的方法,还是读写操作都需要锁定以使其线程安全

非常感谢您抽出时间

1) 我是否成功地使AddString和ToString线程安全

是,如果将
\u stringArrayList
更改为私有

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

3) 是只修改需要锁定的数据的方法,还是读写操作都需要锁定以使其线程安全

读和写。

三者都是(即读/写到最后一个)

但还有更多:

将锁定对象设置为静态,而保护的数据是每个实例字段。这意味着
StringMe
的所有实例都受到保护,尽管它们具有不同的数据(即
\u stringArrayList
的实例)。对于您给出的示例,您可以从
\u locker
中删除
static
修饰符。更准确地说,您通常为一组数据定义一个“锁”,或者为您想要保留的更好的不变量定义一个“锁”。因此,锁的生存期(和作用域)通常应该与数据的生存期(和作用域)相等


此外,为了更好地衡量,您对所保护的数据的可见性不应高于对锁的可见性。在您的示例中,派生实现可以在不获取锁的情况下更改
\u stringArrayList
(因为它受到保护),从而破坏不变量。我将使它们都
私有
,如果必须的话,只通过(正确锁定)方法向派生类公开
\u stringArrayList

不,您没有使这些调用线程安全-因为
\u stringArrayList
字段受到保护。在调用
AddString
ToString
时,子类可以用它做任何事情

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

然后:

更喜欢私有字段-这样可以更容易地对代码进行推理

此外:

  • 现在更喜欢
    List
    而不是
    ArrayList
  • 由于某种原因,您正在使用静态变量锁定。。。因此,即使您有多个
    StringMe
    实例,一次只能有一个线程在
    AddString
  • 使用
    typeof(string)
    Type.GetType(“System.string”)
3) 是只修改需要锁定的数据的方法,还是读写操作都需要锁定以使其线程安全


全部,假设可能有一些操作。如果一切都只是读取,那么就不需要任何锁——但是,否则,即使只有一个写入线程,您的读取线程也可以从数据结构中读取两位数据,而这两位数据是在其间修改过的。(还需要考虑内存模型。)

读卡器也必须锁定-如果只锁定写入器,读卡器下的数据可能会更改,这可能会导致异常。查看
\u锁柜
不必(不应该)是静态的。回答得很好!非常感谢你。这对我来说非常好+1,如果可以的话,我会更多!
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");