[英]Locking to make a class threadsafe with a C# example or is this class 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)是否只需要修改需要锁定的数据的方法,或者是否需要锁定读取和写入操作以使其线程安全?
非常感谢您的参与!
不,您没有使这些调用成为线程安全的 - 因为_stringArrayList
字段受到保护。 在调用AddString
和ToString
子类可以使用它做任何他们喜欢的事情。
例如(正如其他答案声称您的代码是线程安全的。)
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
StringMe
实例, StringMe
只有一个线程可以在AddString
中 typeof(string)
比Type.GetType("System.String")
更清晰 3)是否只需要修改需要锁定的数据的方法,或者是否需要锁定读取和写入操作以使其线程安全?
所有,假设可能有一些操作。 如果所有内容都只是读取,那么您不需要任何锁定 - 但是否则您的读取线程可以读取数据结构中的两位数据,这些数据在两者之间进行了修改,即使只有一个写入线程。 (还要考虑记忆模型的考虑因素。)
1)我是否成功地使AddString和ToString线程安全?
是的,如果您将_stringArrayList
更改为私有
2)在我创建的ToString方法中是否有必要锁定它以使其线程安全?
是
3)是否只需要修改需要锁定的数据的方法,或者是否需要锁定读取和写入操作以使其线程安全?
读和写。
对所有三个都是肯定的(即读/写到最后一个)。
但还有更多:
您将锁定对象设置为static
,而您保护的数据是每个实例字段。 这意味着StringMe
所有实例都是相互保护的,尽管它们具有不同的数据(即_stringArrayList
实例)。 对于您给出的示例,您可以从_locker
删除static
修改器。 更确切地说,您通常要为一组数据定义“锁定”,或者为了保留更好的不变量 。 通常,锁的生命周期(和范围)应该等于数据的生命周期(和范围)。
此外,为了更好地衡量,您保护的数据的可见性不应高于锁定。 在您的示例中,派生实现可以在不获取锁定的情况下更改_stringArrayList
(因为它受到保护),从而打破了不变量。 我会让它们都是private
,如果必须的话,只将_stringArrayList
通过(正确锁定)方法暴露给派生类。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.