0

Sorry if this is a trivial question. But I couldn't find an answer anywhere. I'm writing a program that uses pthreads. One thread acquires a lock (mutex) and then attempts to push data into a synchronized buffer. The buffer has its own mutex which gets acquired once the push() method is invoked.

If the buffer is full and the thread needs to wait on a conditional variable, will the wait call release all acquired locks? Or will it just release the one associated with the conditional variable (which happens to be the last acquired lock)? If it is the latter how can I avoid deadlocks if another thread needs to acquire the first lock?

Edit:

The problem I have is the following. I have two threads, say A and B. Thread A has a for loop which inserts data into a number of buffers. Each iteration inserts an element into one of the buffers. Since this is a thread, it continuously executes this loop within another outer loop for the thread. When B is activated, it manipulates those buffers. But B must not operate on the buffers if A is interrupted by the scheduler in the middle of executing the for loop. Therefore I use a mutex to lock the critical section in A, which is the for loop.

Edit-2:

I have been giving it some thought. And the answer to my problem definitely won't be that the buffers' conditional variable releases the first lock as well. That would mean that the first lock was not even necessary in the first place. If consumer threads (different from Thread B) responsible for removing elements from the buffers are doing their job properly, Thread A would resume at some point and the for loop will complete. Therefore, my problem must lie there. I will take a closer look and update.

informer2000
  • 399
  • 6
  • 20
  • For the first question, the cond-wait will release the mutex you give it. Nothing more. I.e. the lock+cvar pair for your sync-buffer should release its own lock for the wait after initially acquiring it. For the second, if you have to wait for the push-lock and do so by condition, make sure your entrance lock is release *first* (and it sounds like it may not be needed regardless). – WhozCraig Oct 28 '13 at 21:07
  • @WhozCraig Initially, I did not have that first mutex at all. But I believe I need it. Please see my edit above. – informer2000 Oct 28 '13 at 21:41
  • Not 100% sure if this is what your asking but if your using c++ anyway you can ditch pthreads and use [`notify_all`](http://en.cppreference.com/w/cpp/thread/condition_variable/notify_all) – aaronman Oct 28 '13 at 21:46
  • Put that into an SSCCE and it will be much clearer than your description. *Showing* the problem in code will be infinitely more clear then telling us about it. Believe me, the engineers on this form know how to read it and tell you where it is broken. Regardless, my comment prior still stands; you cannot enter into your buffer-push with your outer mutex locked if the only mechanism for releasing the resource you're waiting on (the buffer) cannot acquire means to release it without acquiring the same mutex. That is literally the textbook definition of a deadlock. – WhozCraig Oct 28 '13 at 21:49
  • http://stackoverflow.com/questions/19642938/how-to-provide-a-sequence-of-interleaving-threads-to-show-that-a-code-breaks-and Maybe you guys should hang out together for your assignement. When I was a student we used to do that an it worked wonders. – Sebastien Oct 29 '13 at 01:22
  • @Sebastien This is not an assignment. And I'm not a student. – informer2000 Oct 29 '13 at 21:34
  • @WhozCraig I will try to provide some example code to shed some light on the problem. It is part of a bigger project. – informer2000 Oct 29 '13 at 21:35
  • It sounds like three threads and some simple sample code would likely emulate the scenario you're experiencing, so shoot for that. I think I know what it looks like, but seeing it will help. – WhozCraig Oct 29 '13 at 21:40
  • It's just that almost the exact same question popped up within the span of a few hours. – Sebastien Oct 30 '13 at 00:01

1 Answers1

0

pthread_cond_wait() will release only the mutex that you pass to it, which in your case will be the buffer's mutex acquired earlier within the push() call.

It sounds like you will have the possibility of deadlock in your situation, but that's a consequence of your high-level design. If Thread B cannot be allowed to execute while Thread A is running its for() loop, but within that for() loop Thread A might have to wait for Thread B to consume some data to proceeed, then deadlock is inevitable.

You will need to update your design to account for this. One possibility is to add a reserve() function to your synchronised buffers that reserves space for a subsequent push(), but doesn't add any data. Your Thread A can then go through and reserve the space it needs without holding the outer mutex (since it's not adding any data visible to Thread B yet) - if it has to wait for Thread B to consume some data, it'll do so here. One it has reserved all the space it requires, it can then lock the outer mutex and push the data - this is guaranteed not to have to wait for Thread B, because the space has already been reserved.

caf
  • 233,326
  • 40
  • 323
  • 462