Reputation: 14075
I'm writing a library for multiple projects. And it contains classes that contain and manipulate data. So I thought I should lock this data while a method of those classes is executed. But I also thought if thread safe data manipulation must be done, then let the higher application layer handle locking. What would be the best practice for a library of classes to be used by actual applications later.
Let's say I have a class SpecialList
. What do I do:
?
If I knew how the .NET Framework class List
handles that I would do the same.
Upvotes: 3
Views: 288
Reputation: 391336
If you're designing data structures and types that needs to have a guarantee about thread safety, then sure, put locks and other constructs into those types to uphold those guarantees.
However, locks alone isn't enough.
Take a simple dictionary. Let's say you want to ensure the internal data structure inside the dictionary cannot be corrupted by multiple threads, so you introduce locks. However, if the outside code does this:
if (!dict.ContainsKey(key))
dict.Add(key, value);
Then there is no guarantee here that between the call to ContainsKey
and Add
, some other thread hasn't already added that key to the dictionary.
As such, thread-safe types may entail more things than simple locks. A method that can safely add the key and value to the dictionary if it's not already there, in an atomic operation, and then return a flag telling you what it did, may be needed.
In fact, look here: ConcurrentDictionary.TryAdd.
My advice would be this:
The .NET type List
does not use locks in any way, except for a few select places where thread safety is a concern, specifically the SyncRoot property.
Additionally, writing good thread-safe data types isn't easy. Just throwing in locks everywhere you need them will probably make it more thread-safe, but you will pay a hefty penalty in terms of performance. If a program doesn't need it to be thread-safe when it uses it, you still pay a lot of that price.
Writing performant thread-safe types is harder, and does usually not rely on locks (alone), but instead uses things like spin-waits, specific CPU instructions (some of which are available to .NET code), etc. But this needs highly specialized knowledge about how modern CPU's execute code.
If I were you I would leave thread-safety to the experts, and drop it from your own types, unless you absolutely need it.
Upvotes: 5
Reputation: 35891
I think the answer is dependent on whether you want your library to be thread-safe or not. It seems trivial, but that's how it's done. Consider for example .NET's collections:
List (and other basic collections - not thread safe)
So a good choice seems to be doing both versions, or not thread-safe version only.
Upvotes: 1