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?
2) In the ToString method I've created is it necessary to lock there to make it threadsafe?
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?
Thank you so much for your time!
No, you haven't made those calls thread-safe - because the _stringArrayList
field is protected. Subclasses could be doing whatever they like with it while AddString
and ToString
are being called.
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:
List<T>
to ArrayList
these days StringMe
, only one thread can be in AddString
at a time in total typeof(string)
is much cleaner than 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?
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?
Yes, If you change _stringArrayList
to be private
2) In the ToString method I've created is it necessary to lock there to make it threadsafe?
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?
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. That means that all instances of StringMe
are protected against each other, event though they have distinct data (ie instances of _stringArrayList
). For the example you give, you can remove the static
modifier from _locker
. 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. I would make them both private
and, if you must, only expose _stringArrayList
through (properly locking) methods to derived classes.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.