Is it safe to call a dll function from multiple threads in a single application?
For your DLLs to be thread-safe you need to protect all shared data structures that multiple threads in one process could access concurrently - there is no difference here between writing code for a DLL vs. writing code for an executable.
For multiple processes there is no risk in concurrent access, as each process gets its own data segment for the DLL, so variables with the same name are actually different when seen from different processes. It is actually much more difficult to provide data in a DLL that is the same from different processes, you would basically need to implement the same things you would use for data exchange between processes.
Note that a DLL is special in that you get notifications when a process or a thread attaches to or detaches from a DLL. See the documentation for the DllMain Callback Function for an explanation, and this article for an example how to use this in a Delphi-written DLL. So if your threads are not completely independent from each other (and no shared data is write-accessed), then you will need some shared data structures with synchronized access. The various notifications may help you with properly setting up any data structures in your DLL.
If your DLLs allow for completely independent execution of the exported functions, also do check out the threadvar thread-specific variables. Note that for them initialization and finalization sections are not usable, but maybe the thread notifications can help you there as well.
Short answer:
Yes, it is generally possible to call a DLL function from multiple threads, since every thread has it's own stack and calling a DLL function is more or less the same as calling any other function of your own code.
Long answer:
If it is actually possible depends on the DLL functions using a shared mutable state or not.
For example if you do something like this:
DLL_SetUser(UserName, Password)
if DLL_IsAuthenticated then
begin
...
end;
Then it is most certainly not safe to be used from different threads. In this example you can't guarantee that between DLL_SetUser
and DLL_IsAuthenticated
no other thread makes a different call to DLL_SetUser
.
But if the DLL functions do not depend on some kind of predefined state, i.e. all necessary parameters are available at once and all other configuration is the same for all threads, you can assume it'll work.
if DLL_IsAuthenticated(UserName, Password) then
begin
...
end;
But be careful: It might be possible that a DLL function looks atomic, but internally uses something, which isn't. If for example if the DLL creates a temporary file with always the same name or it accesses a database which can only handle one request at a time, it counts as a shared state. (Sorry, I couldn't think of better examples)
Summary:
If the DLL vendors say, that their DLLs are thread-safe I'd use them from multiple threads without locking. If they are not - or even if the vendors don't know - you should play it safe and use locking.
At least until you run into performance problems. In that case you could try creating multiple applications/processes which wrap your DLL calls and use them as proxies.
Here's the thing - you cannot assume that the DLL's are thread safe if you don't have control over the source code (or documentation stating it is) so therefore you should assume it is not