My recent efforts to implement a thread/ mutex manager ended up in an 75% CPU load (4 core), while all four running threads were either in sleep or waiting for a mutex beeing unlocked.
The specific class is far too large for being posted here entirely, but I could narrow down the cause to the deadlock-safe acquiring of two mutexes
std::unique_lock<std::mutex> lock1( mutex1, std::defer_lock );
std::unique_lock<std::mutex> lock2( mutex2, std::defer_lock );
std::lock( lock1, lock2 );
Another part of the class uses a std::condition_variable
with wait()
and notify_one()
on mutex1
for some code to be executed selectively at the same time.
The simple change to
std::unique_lock<std::mutex> lock1( mutex1 );
std::unique_lock<std::mutex> lock2( mutex2 );
brought the CPU usage down to normal 1-2%.
I Cant believe, the std::lock()
function is that inefficient. Could this be a bug in g++ 4.6.3?
edit: ( example )
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
std::mutex mutex1, mutex2;
std::condition_variable cond_var;
bool cond = false;
std::atomic<bool>done{false};
using namespace std::chrono_literals;
void Take_Locks()
{
while( !done )
{
std::this_thread::sleep_for( 1s );
std::unique_lock<std::mutex> lock1( mutex1, std::defer_lock );
std::unique_lock<std::mutex> lock2( mutex2, std::defer_lock );
std::lock( lock1, lock2 );
std::this_thread::sleep_for( 1s );
lock1.unlock();
lock2.unlock();
}
}
void Conditional_Code()
{
std::unique_lock<std::mutex> lock1( mutex1, std::defer_lock );
std::unique_lock<std::mutex> lock2( mutex2, std::defer_lock );
std::lock( lock1, lock2 );
std::cout << "t4: waiting
";
while( !cond )
cond_var.wait( lock1 );
std::cout << "t4: condition met
";
}
int main()
{
std::thread t1( Take_Locks ), t2( Take_Locks ), t3( Take_Locks );
std::thread t4( Conditional_Code );
std::cout << "threads started
";
std::this_thread::sleep_for( 10s );
std::unique_lock<std::mutex> lock1( mutex1 );
std::cout << "mutex1 locked
" ;
std::this_thread::sleep_for( 5s );
std::cout << "setting condition/notify
";
cond = true;
cond_var.notify_one();
std::this_thread::sleep_for( 5s );
lock1.unlock();
std::cout << "mutex1 unlocked
";
std::this_thread::sleep_for( 6s );
done = true;
t4.join(); t3.join(); t2.join(); t1.join();
}
See Question&Answers more detail:os