简体   繁体   English

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

[英]Locking to make a class threadsafe with a C# example or is this class threadsafe?

I am trying to investigate locking to create a threadsafe class and have a couple of questions. 我正在尝试调查锁定以创建线程安全类并有几个问题。 Given the following class: 鉴于以下课程:

    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) Did I successfully make AddString andToString threadsafe? 1)我是否成功地使AddString和ToString线程安全?

2) In the ToString method I've created is it necessary to lock there to make it threadsafe? 2)在我创建的ToString方法中是否有必要锁定它以使其线程安全?

3) Is it only the methods that modify data that need to be locked or do both the read and write opperations need to be locked to make it threadsafe? 3)是否只需要修改需要锁定的数据的方法,或者是否需要锁定读取和写入操作以使其线程安全?

Thank you so much for your time! 非常感谢您的参与!

No, you haven't made those calls thread-safe - because the _stringArrayList field is protected. 不,您没有使这些调用成为线程安全的 - 因为_stringArrayList字段受到保护。 Subclasses could be doing whatever they like with it while AddString and ToString are being called. 在调用AddStringToString子类可以使用它做任何他们喜欢的事情。

For example (as the other answers claim that your code is thread-safe.) 例如(正如其他答案声称您的代码线程安全的。)

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

Then: 然后:

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

Prefer private fields - it makes it easier to reason about your code. 首选私有字段 - 它可以更容易推理您的代码。

Additionally: 另外:

  • Prefer List<T> to ArrayList these days 这些天首选List<T>ArrayList
  • You're locking with a static variable for some reason... so even if you've got several instances of StringMe , only one thread can be in AddString at a time in total 你出于某种原因使用静态变量锁定...所以即使你有几个StringMe实例, StringMe只有一个线程可以在AddString
  • Using typeof(string) is much cleaner than Type.GetType("System.String") 使用typeof(string)Type.GetType("System.String")更清晰

3) Is it only the methods that modify data that need to be locked or do both the read and write opperations need to be locked to make it threadsafe? 3)是否只需要修改需要锁定的数据的方法,或者是否需要锁定读取和写入操作以使其线程安全?

All, assuming that there might be some operations. 所有,假设可能有一些操作。 If everything is just reading, you don't need any locks - but otherwise your reading threads could read two bits of data from the data structure which have been modified in between, even if there's only one writing thread. 如果所有内容都只是读取,那么您不需要任何锁定 - 但是否则您的读取线程可以读取数据结构中的两位数据,这些数据在两者之间进行了修改,即使只有一个写入线程。 (There are also memory model considerations to bear in mind.) (还要考虑记忆模型的考虑因素。)

1) Did I successfully make AddString andToString threadsafe? 1)我是否成功地使AddString和ToString线程安全?

Yes, If you change _stringArrayList to be private 是的,如果您将_stringArrayList更改为私有

2) In the ToString method I've created is it necessary to lock there to make it threadsafe? 2)在我创建的ToString方法中是否有必要锁定它以使其线程安全?

Yes

3) Is it only the methods that modify data that need to be locked or do both the read and write opperations need to be locked to make it threadsafe? 3)是否只需要修改需要锁定的数据的方法,或者是否需要锁定读取和写入操作以使其线程安全?

Read and write. 读和写。

Yes to all three (ie read/write to the last). 对所有三个都是肯定的(即读/写到最后一个)。

But there is more: 但还有更多:

You make your lock object static , while the data you protect is a per instance field. 您将锁定对象设置为static ,而您保护的数据是每个实例字段。 That means that all instances of StringMe are protected against each other, event though they have distinct data (ie instances of _stringArrayList ). 这意味着StringMe所有实例都是相互保护的,尽管它们具有不同的数据(即_stringArrayList实例)。 For the example you give, you can remove the static modifier from _locker . 对于您给出的示例,您可以从_locker删除static修改器。 To be more precise, you typically define a "lock" for a set of data, or yet better invariants , you want to preserve. 更确切地说,您通常要为一组数据定义“锁定”,或者为了保留更好的不变量 So usually, the lifetime (and scope) of the lock should equal that of the data. 通常,锁的生命周期(和范围)应该等于数据的生命周期(和范围)。

Also, for good measure, you should not have a higher visibility on the data you protect than on the lock. 此外,为了更好地衡量,您保护的数据的可见性不应高于锁定。 In your example, a derived implementation could alter _stringArrayList (since it is protected) without acquiring the lock, thus breaking the invariant. 在您的示例中,派生实现可以在不获取锁定的情况下更改_stringArrayList (因为它受到保护),从而打破了不变量。 I would make them both private and, if you must, only expose _stringArrayList through (properly locking) methods to derived classes. 我会让它们都是private ,如果必须的话,只将_stringArrayList通过(正确锁定)方法暴露给派生类。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM