2

I am new to multi-threading and I have extreme difficulty wrapping my head around mutual exclusion.

So here is the prototype for pthread_mutex_lock

int pthread_mutex_lock(pthread_mutex_t *mutex);

The man page says that The mutex object referenced by mutex shall be locked by calling pthread_mutex_lock().

First of all my understanding is that you use mutex locking to lock a shared resource so that only one thread can access it at any time. For the sake of argument, let's say that the shared resource is a global variable called myVariable. Now if we want to lock myVariable, I should be able to use a locking mechanism to lock myVariable, but what does it mean to lock a mutex object? I mean if I call pthread_mutex_lock(&someMutex), am I locking myVariable or something else?

All to say that if I want to use mutual exclusion, shouldn't I be able to do something like pthread_mutex_lock(myVariable) as opposed to doing pthread_mutex_lock(&someMutex)?

Also how does this someMutex object correspond to myVariable? How does this someMutex object lock access to myVariable?

P.S. Assume that I have declared someMutex before itself.

P.P.S. I had a feeling that this question maybe broad, but then again, it shouldn't be since I am asking about something that actually has a specific answer(correct me if I am wrong).

posixKing
  • 408
  • 1
  • 8
  • 17
  • 1
    Mutex were first described to me to be like the childs game, "Button Button, whose got the Button". You are only allowed to "touch" the "shared resource" if you have the Button... The Mutex is the Button, and you will get it (logically) when your pthread_mutex_lock() succeeds. You can then "read", or "modify" the shared resource. When you are done you "unlock" the mutex, which makes it available to other threads. Note: this is a simplistic/beginners/incomplete description, but it should get you started. – TonyB Nov 08 '16 at 05:18
  • Oh so in that case, can I say use the same mutex for locking of different variables? Say can I call pthread_mutex_lock(&someMutex) for locking myVariable and also yourVariable? Since a mutex is not specific to a particular variable(or resource from what you are saying), I should be able to use a single mutex to handle everything in my program right? – posixKing Nov 08 '16 at 05:23
  • 2
    You could for example have a single mutex controlling all accesses to all Global variables... you must consider the frequency in which all threads may need to access the share resource protected by the Mutex... it is a design decision of how many mutexes you will need and what they will lock. – TonyB Nov 08 '16 at 05:30
  • 1
    Mutexes don't lock shared resources, they lock *sections of code*. It is up to the programmer to make sure any shared resource is only ever touched by code sections locked by a corresponding mutex. – n. m. could be an AI Nov 08 '16 at 09:02

3 Answers3

3

The association between the mutex and what it protects is not known by the mutex, nor does it have to be. Say we have two people who are cooperating and they need to share a car. We don't want one person to try to use the car when the other person is using it. They can enact a simple rule -- don't mess with the car unless you're holding the red turnip. Since only one person can hold the turnip, that ensure that they don't conflict with each other when they try to use the car. The turnip doesn't have to know it's "protecting" the car. So long as they both leave the car alone unless they're the one that holds the turnip, the turnip protects the car.

The mutex is the turnip. Locking the mutex holds the turnip, waiting until the other person puts it down if needed. Unlocking the mutex puts the turnip where the other person can get it.

The variable(s) or object(s) the mutex protects are the car. That the turnip protects the car comes not from anything the turnip does but from everyone complying with the rule not to touch the car unless you have the turnip. Ditto for the mutex protecting objects.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
  • Don't need a turnip to protect a car. There's a simpler rule: Don't drive the car unless you are in the driver's seat. But I can cite a similar example from real life: I've heard of software projects from days gone by when many developers wanted to make changes in a certain shared files. They'd have a special hat, that would hang in the project manager's office, and the rule was, don't edit the file unless you are wearing the hat. – Solomon Slow Mar 06 '17 at 18:33
1

someMutex is basically just a numeric variable, it does not correspond directly to myVariable

general sequential concept

lock(someMutex) {
    while (someMutex != 0) {}
    someMutex = 1;
}

unlock(someMutex) {
    someMutex = 0;
}
Domso
  • 970
  • 1
  • 10
  • 22
1

A mutex protects a region of code so only one thread of execution will execute that region at a time.

A mutex is a basic building block, and it's the responsibility of you to apply this to get the desired result.

If you want to change a shared variable, you could do:

void changeit(int val)
{
    pthread_mutex_lock(&someMutex);
    global_variable = val;
    pthread_mutex_unlock(&someMutex);
}

This part means that only 1 thread at a time will ever execute the code between the locking/unlocking of the mutex. This is to ensure that

  • global_variable = val; is being run atomically, if e.g. 2 assignments were run concurrently, there's no guarantee that the result would be any meaningful value (there is no guarantee that a single assignment statement is carried out atomically or as 1 instruction in the assembly/machine code)

  • Anyone reading the global_variable will do so either completely before or completely after someone changes it, so they do not see any inconsistent value that is in the middle of being changed.

This also means that anyone else accessing(reading and/or writing) to global_variable must also do so while the same mutex is locked, e.g. to read the variable, you can do:

int readit(void)
{
    int val;
    pthread_mutex_lock(&someMutex);
    val = global_variable;
    pthread_mutex_unlock(&someMutex);
    return val;
}

So, someMutex corresponds to global_variable only in the way your code is written, and it relies on you, the programmer, to do it correctly - there is no intrinsic connection between global_variable and someMutex.

If it's meaningful for your program that two variables are connected, and must always be read or written together, a mutex allows you to do that - instead of reading/writing a single variable as the above code shows, you can read/alter 2 variables while the mutex is being held. Again, the mutex knows nothing about those 2 variables, the effect is all in how the code is structured.

nos
  • 223,662
  • 58
  • 417
  • 506