Writing public libraries: Should I let the consumer of the library enforce thread safety?

I’m writing a .NET library which exposes certain public APIs. Currently, I have not enforced thread safety in my library for following reasons apparent to me:

  • locks (Monitor.Enter and Monitor.Exit) are only limited to the AppDomain, so they do not provide synchronization in the inter-process situations.
  • Mutex can be used bigger scope more than the AppDomain, but then I need to struggle with OS-specific limitations such as naming rules for named mutexes.
  • Both lock and Mutex can be useless and cause performance costs if the consumer never wanted to use synchronization.
  • Consumers might need different synchronization mechanism such as Semaphore.
  • MSDN’s Managed threading best practices for class libraries states that avoid synchronization and not make instance data thread safe by default.

From these what I understood was, when it comes to class libraries, it is the consumers’ responsibility to enforce the thread safety in their own way when using that library and the developer should not worry about it.

Is my understanding correct? especially when writing any class library? Also, what would your approach when documenting the library? Should we explicitly state the absence of thread-safety or let the consumers assume that it is not thread safe?

6

You should make your library thread-safe, but that does not mean that you should be sprinkling synchronization primitives around your code base.

For the average library, which is not explicitly designed to communicate across threads, they should be thread-safe to the level that different threads can invoke methods on different objects (possibly of the same type) without interfering with each other or getting incorrect results. This is also known as thread-compatibility.

This can be done in several ways, in order of preference:

  1. Avoid using (writable) shared internal state that might be accessed from multiple threads. If a user decides to create an object and share that across threads, then it is the responsibility of the user to ensure proper synchronization.
  2. If it makes sense, put the internal data that gets shared between objects in thread-local storage.
  3. Put synchronization primitives around the access to the shared internal state.

If your library is specifically designed for inter-thread communication, then you quite quickly end up in the last option mentioned above.

6

Also, what would your approach when documenting the library? Should we explicitly state the absence of thread-safety or let the consumers assume that it is not thread safe?

It might be useful to take a look at the documentation of some common classes, for example List

Thread Safety

Public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.

It is safe to perform multiple read operations on a List, but issues can occur if the collection is modified while it’s being read. To ensure thread safety, lock the collection during a read or write operation. To enable a collection to be accessed by multiple threads for reading and writing, you must implement your own synchronization. For collections with built-in synchronization, see the classes in the System.Collections.Concurrent namespace. For an inherently thread-safe alternative, see the ImmutableList class.

This forms the basis of my expectations:

  1. Static members should be thread safe
  2. Objects should not have any special thread affinity. I.e. you can create an object on one thread, and use it from another.
  3. No hidden, unsynchronized, shared state. If shared state is needed, make this explicit in some way, or make sure access is synchronized. I.e. locking the object is sufficient for thread safety.
  4. If the class is named “Concurrent”, “Threadsafe”, or “Immutable”, it should be thread safe.

It is especially important to note any deviations from expectations. But I would recommend to be explicit in the documentation. There is few things worse than having to guess if something is safe or not, and some things might not be obvious, like if a method modifies internal state or not.

UI related objects are one notable exception from these general rules.

I would suggest making a general statement of the threading model used in your library, link to this from any type documentation to make it easier to find, and note any deviations.

It is your responsibility to make the library useable and useful for the consumer. It doesn’t have to be thread safe, but you need make that very clear in the documentation and explain what the expected usage pattern should be

A common way libraries that are not thread safe for multiple threads accessing a single object is to handle this is by building the library in a way that instantiating a new object per thread is safe (i.e. doesn’t share configurations via static variables or disk). In most cases the consumer can trivially handle this by changing to a transient scope on their IoC. The key part is letting the consumer know they need to do this.

It depends

I am contributing to a library that is thread safe by default. We decided to do this because making it thread safe by default makes our developer lives easier, reduces client misuse, there is no inherent performance gain by not being thread safe, and making it thread safe from the caller side is much harder while being somewhat trivial on our side. It also doesn’t require complicated things like system wide mutex.

If you do go down the thread safe path, be careful to avoid lock statements, as these may cause unexpected behaviors in async methods.

Regarding the MSDN guideline: Microsoft themselves distribute thread safe classes e.g: https://learn.microsoft.com/en-us/dotnet/api/system.collections.concurrent?view=net-8.0

By thread safe, this means:

  1. No shared state between different instances of the same class.
  2. Accessing the same object from different threads will not make the object’s internal state to become corrupt. It may result in unusual behavior, but not result in a crash or otherwise unrecoverable situation.
  3. Threads reading a property of the objects will get the latest written value of that property, when reading and writing occur on different threads. If a 2nd write occurs right after the read, then the read will not see the modified data.
  4. If a particular operation needs to happen on a specific thread (most commonly on the UI thread), the object will automatically handle that situation, even if the call comes from the wrong thread.

However, this only applies to the specifics of this library. My suggestion is to try and go thread safe if your library is likely to be used in a multithreaded environment, at the very least try to prevent corrupted states due to thread races. This will at the minimum save you time trying to educate people on how to avoid crashes caused by multithreading.

5

“Enforce thread safety” is difficult depending on what you are doing.

For example, if two threads read the same data, that should not crash, and give the same data to both threads.

What if one thread tries to read data while the other tries to change it, as close together as possible? You can’t guarantee that the data read is the old of the new data. You can guarantee that it doesn’t crash and is either the old or the new data. But either way it’s a problem. So do you want to make any guarantees?

It’s hard to decide what guarantees you should give.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật