ZisIsNotZis
ZisIsNotZis

Reputation: 1750

Lock two mutex at same time

I'm trying to implement a multi-in multi-out interthread channel class. I have three mutexes: full locks when buffer is full. empty locks when buffer is empty. th locks when anyone else is modifying buffer. My single IO program looks like

operator<<(...){
  full.lock()        // locks when trying to push to full buffer
  full.unlock()      // either it's locked or not, unlock it
  th.lock()
  ...
  empty.unlock()     // it won't be empty
  if(...)full.lock() // it might be full
  th.unlock()
operator>>(...){
  // symmetric
}

This works totally fine for single IO. But for multiple IO, when consumer thread unlocks full, all provider thread will go down, only one will obtain th and buffer might be full again because of that single thread, while there's no full check anymore. I can add a full.lock() again of course, but this is endless. Is there anyway to lock full and th at same time? I do see a similar question about this, but I don't see order is the problem here.

Upvotes: 3

Views: 6364

Answers (4)

Slava
Slava

Reputation: 44288

Functonality you try to achieve would require something similar to System V semaphores, where group of operations on semaphors could be applied atomically. In your case you would have 3 semaphores:

  • semaphore 1 - locking, initialized to 0
  • semaphore 2 - counter of available data, initialized to 0
  • semaphore 3 - counter of available buffers, initialized how much buffers you have

then push operation would do this group to lock:

  • check semaphore 1 is 0
  • increase semaphore 1 by +1
  • increase semaphore 2 by +1
  • decrease semaphore 3 by -1

then

  • decrease semaphore 1 by -1

to unlock. then to pull data first group would be changed to:

  • check semaphore 1 is 0
  • increase semaphore 1 by +1
  • decrease semaphore 2 by -1
  • increase semaphore 3 by +1

unlock is the same as before. Using mutexes, which are special case semaphores most probably would not solve your problem this way. First of all they are binary ie only have 2 states but more important API does not provide group operations on them. So you either find semaphore implementation for your platform or use single mutex with condition variable(s) to signal waiting threads that data or buffer is available.

Upvotes: -1

Joseph Artsimovich
Joseph Artsimovich

Reputation: 1519

No, you can't atomically lock two mutexes.

Additionally, it looks like you are locking a mutex in one thread and then unlocking it in another. That's not allowed.

I suggest switching to condition variables for this problem. Note that it's perfectly fine to have one mutex associated with multiple condition variables.

Upvotes: 2

Rama
Rama

Reputation: 3305

Yes, use std::lock(full , th);, this could avoid some deadlocks

for example: thread1:

full.lock();
th.lock();

thread2:

th.lock();
full.lock();

this could cause a deadlock, but the following don't:

thread1:

std::lock(full, th);

thread2:

std::lock(th, full);

Upvotes: 7

skypjack
skypjack

Reputation: 50568

No, you cannot lock two mutexes at once, but you can use a std::condition_variable for the waiting threads and invoke notify_one when you are done.
See here for further details.

Upvotes: 0

Related Questions