Difference between global / local / static Mutex?

Viewed 2238

A mutex is used to prevent two or more threads to access the same resource (file, variable, ..) at the same time. This prevents a race condition to happen.

Every thread has its own stack. This means when a thread calls a function, the thread will have a unique copy of the local variables defined in this function. But if a local variable is defined as static, only one copy of this variable will be created and this copy will be accessed by all threads.

  • Does this mean that a local NON-static mutex is useless?

  • Can a static local mutex be useful? Maybe for guarding a static local variable?

  • How does defining a global mutex as static make as a difference?

3 Answers

A non-static local mutex can still be useful: If you have a main thread that creates the other threads and waits for them to finish, the mutex can be a local variable in the main thread, and it would pass a pointer to that mutex to the other threads. This works only if it's guaranteed that the main thread outlives the others.

If the mutex variable is declared as static inside your thread function, it will be shared between different threads which use this function, and they can use it for synchornization. This is because static variables have the same lifetime as global variables (and only one unique copy). However, this only works if your threading library doesn't require a function call to initialize the mutex, as there wouldn't be a good place to do that initialization from.

Another option is to dynamically allocate the mutex, or, more commonly, to have it as a member of a dynamically allocated struct. You can then pass a pointer to the mutex (or containing struct) to all the threads which need it.

As for your last question: Defining a global variable as static means that it's only visible in the current translation unit. It doesn't affect its lifetime, so will work similarly to non-static globals for this use-case (as long as you only need to access it in one .c file).

Local to a thread callback function is useless - a mutex that isn't shared between multiple functions doesn't make much sense. You can however make it local static for the sake of reducing scope/global namespace clutter, then share it between functions through pointers. Such as for example have the main thread create it and then pass it along to different threads during creation. This often makes the most sense - to have one thread responsible for the creation and clean-up of all threads and mutexes etc in the project.

A classic bug is to have one thread create resources by passing along local variables with automatic storage (saved on stack) to threads, then that thread goes out of scope and the variables turn invalid. Therefore it is custom to either use static or dynamic memory allocation for such variables, so that they persist throughout the whole execution of the program.

The term "global" is confusing and poorly-defined. Usually it means global to the whole project. Where as a variable declared outside any function has file scope, but such a variable may have either external or internal linkage. External meaning "global". But if you declare a file scope variable static, it gets internal linkage and is only visible to the .c file where it was declared. This is a good thing, because it reduces scope and prevents spaghetti programming with global variables.

static in C means that it's visible in only in that file. Thus, if all functions that use static mutex located in the same file, then they will share the same mutex. If mutex is accesses from functions in multiple files, then it must be global. Typically you have a global state variable and associated with it global mutex.

// in types.h
typedef struct {
  pthread_mutex_t lock;
  int val;
} state_t;


// in shared.h
extern state_t global_state;

// in code
#include "types.h"
#include "shared.h"

int foo() {
   pthread_mutex_lock(global_state.lock);
   global_state.val = STATE_FOO;
   pthread_mutex_unlock(global_state.lock);
}

A mutex per function makes no sense.

Related