I have this static C library that I need to run multithreaded(the threads have no interaction with each other, I just need multiple of them at the same time to get stuff done faster). Further more I've wrapped the c library into a c++cli library which is then used by the c# main application.
Since the static library doesn't respond well to multiple threads running through it (which is out of my control, I don't have the source for its dependencies), I have resorted to copying(with slight variations) the whole thing multiple times and putting another wrapper between the c++cli library(and its copies) and the c# application that emulates the copies as up to 8 instances of the object. It works but its rather crude and cumbersome to make any changes to the functionality of the library.
Does anybody know of a simpler way to achieve the same effect? Best guess I have is that some static piece of memory is where the conflict arises between multiple threads working in the same library, is there a way to force all the static variables to be thread specific? (without the ability to go in an add declspec thread to them).
Since you are using your C library from C# via C++/CLI layer, it sounds like your link relationships look like this:
(C# application)--dynamic-->(C++/CLI DLL)--static-->(C library)
Background:
Because you stated that you have no way of modifying or otherwise fixing your C library, you really have no way of solving the thread-safety problem without duplicating the C library in memory somehow, which will effectively duplicate the global data which is/are certainly causing the threading conflicts.
No matter how you look at it, your only way of solving this via DLL duplication (your current approach) will require you to know how many duplicates you need ahead of time, and each one of those DLLs will need slightly different exported symbol names (for example, each will need a different class or namespace name for your C++/CLI managed object class). As you stated, this is indeed crude (and I will add hard to manage and impossible to scale).
Solution:
I think your better and cleaner option is via EXE duplication. For this, you will insert a new EXE in front of your C++/CLI DLL and link to it dynamically via IPC mechanism of your choice (IPC Mechanisms in C# - Usage and Best Practices). Lets call this EXE your service EXE. If you instantiate a service EXE for each thread in your main C# application, then each service EXE will load its own copy of the C++/CLI DLL and consequently its own version of the C library. This means that each thread is operating on a copy of the C library via a service EXE.
Here is what your link relationships would look like:
(C# application)--IPC-->(C# service EXE)--dynamic-->(C++/CLI DLL)--static-->(C library)
In physical file terms, it would look like this:
MainApp.exe--IPC-->ServiceApp.exe--dynamic-->CppCliWrapper.dll
To optimize this solution, you should try to avoid heavy thread creation / deletion since that involves creation / deletion of a service EXE. For example, you might pre-allocate X threads on startup and use those threads throughout your application lifecycle. You might also consider batching your operations to optimize the IPC overhead. All of this depends on the needs and details of your application.
To take this even further, you could potentially scale this solution across machines if you choose an IPC mechanism that works over TCP/IP. You could then farm out your operations across as many machines as you like. This is how a lot of companies turn DLLs into horizontally scalable services. It's not as easy as it sounds, but food for though in case you need to scale this thing up.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With