2

If I understand correctly, then foo1() fails to unlock &private_value_. As a result, foo2()'s thread_mutex_lock does not work since foo1() never released it.

What are the other consequences?

int main ( ... )

foo1();
foo2();

return 0;
}

foo1()
{
 pthread_mutex_lock(&private_value_);
 do something 
 // no unlock!
}

foo2()
{
 pthread_mutex_lock(&private_value_)
 do something
 pthread_mutex_unlock(&private_value_);
}
caf
  • 233,326
  • 40
  • 323
  • 462
Kevin Meredith
  • 41,036
  • 63
  • 209
  • 384
  • 2
    Well, the mutex does work, but foo2 will never acquire the lock. –  Aug 12 '10 at 19:15
  • So we'll do something in foo1(), but after that main() halts? – Kevin Meredith Aug 12 '10 at 19:18
  • 4
    Erm, yes - this is what mutexes are for. –  Aug 12 '10 at 19:20
  • Could you please state your question right? This has nothing to do with C++ nor with C as a language but is a property of POSIX. pthread (= POSIX thread) – Jens Gustedt Aug 12 '10 at 19:37
  • 2
    It all depends on how the mutext was created. pthreads allows several different types of mutex some of which would cause deadlock above while others would work fine. See: http://opengroup.org/onlinepubs/007908775/xsh/pthread_mutex_lock.html – Martin York Aug 12 '10 at 19:58

8 Answers8

5

There seems to be some confusion here between how the program should have been written and how the program, as currently written, will behave.

This code will cause deadlock, and this does not indicate that there is something wrong with how the mutexes are working. They're working exactly how they are supposed to: If you try to re-acquire a non-recursive mutex that is already locked, your code will block until the mutex is unlocked. That's how it's supposed to work.

Since this code is single-threaded, the blocking in foo2 will never end, and so your program will deadlock and not progress. That is most likely not how the program should work (because it's not a very useful program that way). The error is not in how the mutexes are functioning, but in how the programmer chose to employ them. The programmer should have put an unlock call at the end of foo1.

Tyler McHenry
  • 74,820
  • 18
  • 121
  • 166
  • 3
    No you are wrong this will not necessarily block. `If the mutex type is PTHREAD_MUTEX_RECURSIVE, then the mutex maintains the concept of a lock count. When a thread successfully acquires a mutex for the first time, the lock count is set to one. Every time a thread relocks this mutex, the lock count is incremented by one.` So if it is initialized with an attibute that sets `PTHREAD_MUTEX_RECURSIVE` the bug of this program will be hidden and the behavior will seem "normal". – Jens Gustedt Aug 12 '10 at 19:43
  • 3
    I'm aware of that. Did you read the part where I wrote "non-recursive mutex"? Additionally, the OP's description of the behavior that he observed indicates that the mutex is in this case not recursive. – Tyler McHenry Aug 12 '10 at 19:59
  • @Tyler: Didn't mean to offend you, but you put the "will" in emphs, and I wanted to make this point clear. – Jens Gustedt Aug 12 '10 at 20:32
  • If the mutex is an error-checking type, it won't deadlock either - the second attempt to lock will return `EDEADLK` (which would fit the OP's characterisation of the second `pthread_mutex_lock` "not working"). – caf Aug 13 '10 at 00:26
  • @Jens not quite... it's still short one `unlock()` of being right... it won't deadlock since there's only one thread but it's a deadlock waiting to happen. (all this assuming it was changed to recursive locks, which as said is not what the question is about) – Spudd86 Nov 22 '10 at 19:58
4

The mutex works fine. It's doing what it is meant to do. The thread will block after foo1() exits until the mutex is obtained by foo2.

San Jacinto
  • 8,774
  • 5
  • 43
  • 58
  • But isn't foo1() supposed to unlock the mutex it acquired? How can foo2() ever obtain the mutex if foo1() never releases it? – Kevin Meredith Aug 12 '10 at 19:21
  • 1
    foo2 will NEVER obtain it until foo1 releases it. Foo1 itself does not own the mutex. I assume the mutex is part of a class and the mutex lock/unlock statements are indeed operating on the same common mutex. In your code, if you do not explicitly unlock the mutex, it is considered locked and nothing else can obtain the lock --not even the same thread. – San Jacinto Aug 12 '10 at 19:22
  • 1
    Are you perchance coming from a C# or java background where monitors offer scoped locks that are managed automatically? This is not the case when using the prthread library calls. – San Jacinto Aug 12 '10 at 19:24
  • 4
    Though there about a zillion C++ libraries that do exactly this. –  Aug 12 '10 at 19:25
1

This is why people migrate to languages that offer scope-based solutions, like C++ and RAII. The mutex is working as intended, but the writer of the first function forgot a small call, and now the application halts.

Puppy
  • 144,682
  • 38
  • 256
  • 465
1

It's a bug if a lock is taken on a mutex and nothing ever releases the lock.

However, that doesn't necessarily mean that foo1() has to release the lock, but something must.

There are patterns where one function will acquire a lock, and another will release it. But you need to take special care that these more complex mutex handling patterns are coded correctly. You might be looking at an example of this (and the boiled-down snippet in the question doesn't include that additional complexity).

And as Neil Butterworth mentioned in a comment, there are many situations in C++ where a mutex will be managed by an RAII class, so the lock will be released automatically when the 'lock manager' object gets destroyed (often by going out of scope). In this case, it may not be obvious that the lock is being released, since that is done as a side effect of the variable merely going out of scope.

Michael Burr
  • 333,147
  • 50
  • 533
  • 760
1

No, it does not necessarily block. All depends on your private_value_ variable. pthread_mutex_t can show different behavior according to the properties that were set when the variable was initialized. See http://opengroup.org/onlinepubs/007908775/xsh/pthread_mutex_lock.html

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
1

To answer the question:

There are no other consequences other than a deadlock (since your example is single threaded and makes the calls synchronously)..

carribus
  • 66
  • 5
0

If only foo2 gets called everything will run normal. If foo1 gets called then, if foo2 gets called or any other function that requires the mutex it will lock up forever.

crazyx
  • 17,806
  • 1
  • 17
  • 8
0

The behavior of this code depends on the type of the mutex:

  • Default: Undefined behavior (locking an already-locked mutex).
  • Normal: Deadlock (locking an already-locked mutex).
  • Recursive: Works, but leaves the mutex locked (since it's locked twice but only unlocked once).
  • Error-checking: Fully works, and unlocks the mutex at the end (the second call to lock fails with EDEADLK, and the error value returned is ignored by the caller).
R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711