Giovani
Giovani

Reputation: 211

Why it does NOT occur deadlock?

The code is acquiring the same mutex from two different threads at the same time. I understand that a deadlock should occur. Why it is not happening?

#include <iostream>
#include <thread>
#include <queue>
#include <mutex>
#include <condition_variable>

template <typename T>
class SafeQueue
{
 public:
  T pop()
  {
    std::unique_lock<std::mutex> mlock(mutex_);
    std::cout << "lock pop()" << std::endl;
    while (queue_.empty())
    {
      cond_.wait(mlock);
      std::cout << "lock pop awake. Items: " << queue_.size() << std::endl;
    }
    auto item = queue_.front();
    queue_.pop();
    std::cout << "returning from pop" << std::endl;
    return item;
  }

  void push(const T& item)
  {
    std::unique_lock<std::mutex> mlock(mutex_);
    std::cout << "lock push()" << std::endl;
    queue_.push(item);
    mlock.unlock();
    cond_.notify_one();
  }
 private:
  std::queue<T> queue_;
  mutable std::mutex mutex_;
  std::condition_variable cond_;
};

SafeQueue<int> queue;

void pop()
{
    std::cout << "popping..." << std::endl;
    std::cout << "popped: " << queue.pop() << std::endl;
}

int main()
{
    std::thread consumerThread(pop);
    std::this_thread::sleep_for(std::chrono::seconds(3));
    std::cout << "main thread will push" << std::endl;
    queue.push(2);
    std::cout << "pushed" << std::endl;
    consumerThread.join();
    std::cout << "end" << std::endl << std::endl;
}

My output is:

popping...

lock pop()

main thread will push

lock push()

pushed

lock pop awake. Items: 1

returning from pop

popped: 2

end

Upvotes: 2

Views: 132

Answers (3)

Damien Saint-Macary
Damien Saint-Macary

Reputation: 64

This statement:

 cond_.wait(mlock);

actually unlocks the mutex during the wait, and reacquires the lock once signaled. That's why you don't have any deadlock.

Upvotes: 4

CristianTM
CristianTM

Reputation: 338

What is happening is that std::condition_variable::wait is releasing the mutex. The thread then waits until the notify_one call, that will release the condition and re-acquire the mutex.

http://en.cppreference.com/w/cpp/thread/condition_variable/wait

"There must be at least one thread that is waiting for a condition to become true. The waiting thread must first acquire a unique_lock. This lock is passed to the wait() method, that releases the mutex and suspends the thread until the condition variable is signaled. When that happens the thread is awaken and the lock is re-acquired." http://www.codeproject.com/Articles/598695/Cplusplus-threads-locks-and-condition-variables

Upvotes: 3

Mark B
Mark B

Reputation: 96311

A deadlock requires TWO mutexes to be acquired in different orders in different threads. I only see a single mutex in your code.

Upvotes: 0

Related Questions