Mutex creation in multithreaded library

Started by
8 comments, last by Hodgman 10 years, 10 months ago

Hello,

I think I have a kind of chicken-egg problem:

I have a library (dll) that is pure C and that is supposed to be thread-safe.

How do I initialize it? I mean, at some point I need to call


globalMutex=CreateMutex(0,FALSE,0);
do some other initializations here

The above section of code should be run only the very first time someone calls a function in the library. But what if several threads call the library at the same time? Best would be to have a mutex to make sure the initialization happens only once, but mutexes need to be initialized...

Any idea?

Advertisement

Doesn't it get called only once, when you load library? So just load it before creating any threads.

Most libraries solve this by requiring you to explicitly call some kind of init() function.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

If you target windows, you could use DllMain.

for other platform there are alternatives (see this for example)

globalMutex=CreateMutex(0,FALSE,0);

Do you really need a Windows Mutex?

Yes, the Windows Mutex will always work, but it introduces a kernel-level stall every time you create it. The thing takes about a full microsecond just to lock. And heaven help your app if there is lock contention.

It is like installing a stop sign in the middle of a race track. It will work at ensuring every process running on the computer obeys the lock, but at a terrible system-wide performance cost.

Wherever possible use a lockless solution or design around it. Don't get in the problem to begin with.
If you need to share data, don't lock and instead use atomic primitives.
If you need to share locked data, use an interlocked variable.
If you need to share more data than an interlocked variable can handle, use a critical section.
If you absolutely must coordinate data between many processes, use a system mutex.

The atomic operations and lockless solutions have no additional cost.
Interlocked operations cost around 5-10 nanoseconds, potentially a few more if there is contention.
Critical sections cost around 20-50 nanoseconds to enter and lock, plus potentially many microseconds (or worse) if there is contention.
A Windows Mutex costs around 500-1000 nanoseconds to enter and lock because it is done at the kernel level. It can take many milliseconds (or worse) if there is contention.

Choose the right synchronization objects for your needs. A full kernel-level Mutex object is usually the wrong selection.

Thanks for all the replies.

The library can actually be compiled for many different platforms (also microcontrollers), and is allready in use. For that reason I cannot use an additional function that initializes everything.

I was just wondering if there is an extremely lightweight lock one can build, that is not OS dependent?

Or at least a random/timed mechanism that will reduce the chance for 2 threads entering the initialization section?

I was just wondering if there is an extremely lightweight lock one can build, that is not OS dependent?

Boost has a pretty good collection of synchronization tools, although it may not be supported on your microcontrollers.

You can build an atomic one-time lock on any CPU that supports atomic compare and swap:

// Some global
int counter = 0;
 
if (CompareAndSwap(counter, 1) == 0) {
   // Do initialization
}
 
// Carry on
[edit] For completeness: you also need a spinlock that waits until initialization is completed:
// Another global
int initdone = 0;

if (CompareAndSwap(counter, 1)) {
// init
// atomic set initdone to 1
}

while (AtomicCompare(initdone, 0)) {
// No-op
}

// Carry on

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

Thanks again!

I also found a platform-independent way of doing it: the Peterson's algorithm

This topic is closed to new replies.

Advertisement