Posted by: Airtower | 2010-07-27

What is a mutex?

It took me a while to understand what a mutex really is, so here is my attempt to write a simple explanation.

So, what is a mutex?

“Mutex” is short for “mutual exclusion.” Technically, when talking about “a mutex” I’m referring to a special type of variable that can be in one of two states: “locked” or “unlocked”. Mutexes are used to prevent access conflicts between different threads in an application. The principle of using a mutex is simple: A thread locks the mutex before a potentially conflicting operation, does the operation, then unlocks the mutex again. It is important to understand that a mutex does not “magically” protect anything. It is like a baton: If one thread has the mutex locked, the next one trying to lock it will have to wait until it becomes unlocked. All of this depends on the programmer putting the lock and unlock calls in the right places.

When do I need a mutex?

You should use a mutex wherever concurrent access to a variable by different threads can be a problem. Read-only accesses are okay, but writes should usually be protected. Note that in this case reads must be protected as well to prevent reading during a “halfway done” write. There are exceptions, if you want to learn about them look for “atomic operations.”

Example

So, on to a little example that will launch a thread for each command line argument. Each thread will print its argument with a line number in front. Note that the example uses declarations inside for-loop initialization, so you’ll need a C99 compatible compiler if you want to compile it, e.g.:

$ gcc -std=c99 -pthread mutex_example.c

#include <pthread.h>
#include <stdio.h>

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
unsigned int count = 0;

void *thread_function(void *arg)
{
	pthread_mutex_lock(&mutex);
	int i = count;
	count = i + 1;
	printf("%i: %s\n", i, (char *) arg);
	pthread_mutex_unlock(&mutex);
	return NULL;
}

int main(int argc, char **argv)
{
	int n = argc - 1;
	pthread_t threads[n];
	for (int i = 0; i < n; i++)
		pthread_create(&threads[i], NULL,
			thread_function, argv[i + 1]);
	for (int i = 0; i < n; i++)
		pthread_join(threads[i], NULL);
	return 0;
}

The line numbers make only sense if they are consecutive, so we need to make sure that the line count does not change until the line was printed. Otherwise, two threads could read the same current count and write back the same incremented value, resulting in a too low number. So, each thread does this:

  1. Get the mutex.
  2. Get and increment the line number.
  3. Print the line.
  4. Unlock the mutex.

If there is more than one thread, one of them will get the mutex first and the others will have to wait until it is done. I know this could be done in a much shorter way which would not require a mutex to be thread-safe (bonus points if you know, too), but I think it shows the idea behind using mutexes. 😉

Caveats

I don’t claim this list to be conclusive, but you should look out for the following when using threads and mutexes:

  • Deadlocks: Thread one has mutex one locked and is waiting to get mutex two, while thread two has mutex two locked and is waiting to get mutex one.
  • Concurrency problems that are not results of concurrent variable access and can not be solved by mutexes.
  • Using mutexes where not necessary. This should not break the program, but it can hurt performance.
  • Obvious, but still: forgetting places that would need a mutex.

Have fun with threads!

Advertisements

Responses

  1. So when you say “a mutex does not “magically” protect anything. It is like a baton: If one thread has the mutex locked, the next one trying to lock it will have to wait until it becomes unlocked.”, does that mean, that in order for it to work, both threads that want to write to the data need to use it (where I guess I was assuming that if one used one the others would all be automatically excluded)?

    Although still not sure whether I should be bothering with them (though you did say “writes should usually be protected.”)

    • “[…] does that mean, that in order for it to work, both threads that want to write to the data need to use it”
      Yes, exactly.


Leave a Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Categories

%d bloggers like this: