I need to work with the same mutex and unique_lock across the main function and class instances. However, I am having trouble assigning the mutex/unique_lock address to a class member variable (that is a mutex&).
This is what I have:
Worker.h
class Worker
{
private:
std::mutex &m_mu;
std::unique_lock<std::mutex> &locker;
public:
void start(std::mutex &mu, std::unique_lock<std::mutex> &locker);
};
Worker.cpp
void Worker::start(std::mutex &mu, std::unique_lock<std::mutex> &locker)
{
this->mu = mu; // error
this->locker = locker; // error
}
I tried doing this->mu(mu); but that doesn't work either. Is there anything I can do to make this work?
Thanks.
You need to pass the mutex reference when you construct your class.
Worker::Worker(std::mutex &mu, std::unique_lock<std::mutex> &locker)
:m_mu(mu), locker(locker)
{}
That's the only place you can initialize a reference. Once it's constructed, you cannot change what it references.
Why do you need the locker? The mutex makes the synchronization, the lock is just a RAII object to ease acquiring the mutex.
You don't need to pass the lock object to the function. As long as the class is referring to the correct mutex you can lock the mutex inside the function like this:
class Worker
{
private:
std::mutex& m_mu;
public:
Worker(std::mutex& mu): m_mu(mu) {} // bind reference during initialization
void start();
};
// Worker.cpp
void Worker::start()
{
std::unique_lock<std::mutex> locker(m_mu); // lock the shared resource
// Do something with it here
}
int main()
{
std::mutex mu;
std::vector<Worker> workers(4, Worker(std::ref(mu)));
// etc...
}
Related
I'm watching a video about mutex and RAII.
In the video the author explains that a good application of RAII (using an object to manage a resource) is a mutex. He has the following class:
class Lock {
private:
Mutext_t* m_pm;
public:
explicit Lock(Mutex_t* pm) { Mutex_lock(pm); m_pm = pm; };
~Lock() { Mutex_unlock(m_pm); };
};
I'm not sure how he implemented Mutex_unlock and Mutex_lock.
My question is: Is the following implementation comparable, and will it achieve the desired result of unlocking a mutex should the function that class object is instantiated in throw an exception?
mutex mu;
class Lock { // Lock will be destroyed if stack is unwound
private:
mutex* p_Mutex;
public:
explicit Lock(mutex* Mutex) {
lock_guard<mutex> u_Lock(*Mutex);
p_Mutex = Mutex;
};
};
void functionB() {
Lock myLock(&mu);
// .. Do stuff that throws an error.
// Unwind stack and destroy myLock, unlocking the mutex?
}
This is very much a simple implementation for learning purposes. Thanks for your help.
I have a problem with passing a mutex to my class. I have a class named Test with the a member variable called m_Mutex. In the constructor I want to transfer the parameter mutex to m_Mutex.
My class:
#include <mutex>
class Test
{
public:
Test(mutex &mtx) :
m_Mutex(mtx)
{
}
private:
mutex m_Mutex;
};
My main:
int main()
{
mutex mutex1;
Test t(mutex1);
return 0;
}
Error:
function "std::mutex::mutex(const std::mutex &)" (declared at line 88
of "c:\Program Files (x86)\Microsoft Visual
Studio\2017\Professional\VC\Tools\MSVC\14.11.25503\include\mutex")
cannot be referenced -- it is a deleted function
Why am I getting this error and how can I fix it that I am able to pass the mutex?
In short terms: you can't. Mutexes are neither copyable nor movable. And they aren't for a good reason. If however you want to achieve this nontheless, you might pass it by using a unique_ptr:
class A {
unique_ptr<mutex> mutexPtr;
A(unique_ptr<mutex> ptr) : mutexPtr(std::move(ptr)) { }
};
A a{std::make_unique<mutex>()};
Note that if you want to share the mutex between different objects, you should use shared_ptr or weak_ptr instead.
In the constructor I want to transfer the parameter mutex to m_Mutex
Unfortunately you can't. std::mutex is not copyable and not moveable. One thing you can do if you want to declare the mutex somewhere else is to store a reference to the mutex like
class Test
{
public:
Test(mutex &mtx) :
m_Mutex(mtx)
{
}
private:
mutex& m_Mutex;
};
#include <mutex>
class Test
{
public:
Test(std::mutex &mtx) :
m_Mutex(mtx)
{
}
private:
std::mutex &m_Mutex; // note the "&"
};
int main()
{
std::mutex mutex1;
Test t(mutex1);
return 0;
}
Just keep mutex inside your class (probably as static member) and if you need to allow other classes to use it provide access:
class Test
{
public:
Test() {}
std::mutex &mux() { return m_Mutex; }
private:
mutex m_Mutex;
};
or even this:
class Test {
public:
using lock_t = std::scoped_lock<std::mutex>;
Test() {}
lock_t lock() { return lock_t( m_Mutex ); }
private:
mutex m_Mutex;
};
usage:
Test t;
{
auto lock = t.lock();
// object t is locked till end of the block
}
Just make it a reference
Your mutex must be the same for all instances of your class, if it's not the case the lock you do in one instance of your class won't be active for the other one.
#include <mutex>
#include <iostream>
using namespace std;
class Test
{
public:
Test(mutex &mtx) :
m_Mutex(mtx)
{
m_Mutex.lock();
i++;
cout << "Test " <<i<<endl;
m_Mutex.unlock();
}
private:
mutex& m_Mutex;
static int i;
};
int Test::i =0;
int main()
{
mutex mutex1;
Test t1(mutex1);
Test t2(mutex1);
return 0;
}
see it live : https://wandbox.org/permlink/6YJFG3MI7m7RbfoL
To implement the logic when contructed object starts background thread for real work, I'm using a pattern like this (simplified):
class A {
std::thread t{&A::run, this};
std::atomic_bool done;
// variables are the question about
std::vector<std::thread> array_for_thread_management;
// ... and other members
protected:
void run() {
...
array_for_thread_management.push_back([](){...});
...
}
public:
A() = default;
// all other constructors deleted because of used
// some members like std::atomic_bool done;
~A() {
done = true;
bi::named_condition cnd{bi::open_only, "cnd"};
cnd.notify_one();
if (t.joinable())
t.join();
for(std::thread& worker : array_for_thread_management) {
if (worker.joinable()) worker.join();
}
}
};
If I'm adding a push of child threads in primary background thread into a vector in run() member, the object hangs on destructor.
even there is no real threads in a vector, just started this without connections from outside and try to stop this by destructor
Of course, once you have this pointer in your run method, you can access class members via this pointer. I guess the problem with your code is that the thread is spawned before any other members are initialized, as it is the first member in your class definition. I suspect with the following definition of class A you'll have no problems with accessing member variables:
class A {
std::atomic_bool done;
// variables are the question about
int i;
std::string s;
std::vector<std::string> v;
// and only after everything above is initialized:
std::thread t{&A::run, this}; // spawn a thread
// ...
}
However, personally I would prefer having a separate method start() which spawns a thread to spawning it inside class constructor implicitly. It may look like this:
class A
{
std::unique_ptr<std::thread> t;
std::atomic<bool> some_flag;
public:
void start()
{
t.reset(new std::thread(&A::run, this));
}
private:
void run()
{
some_flag.store(true);
}
};
I'm new to the boost threads library. I have a situation where I acquire a scoped_lock in one function and need to wait on it in a callee.
The code is on the lines of:
class HavingMutex
{
public:
...
private:
static boost::mutex m;
static boost::condition_variable *c;
static void a();
static void b();
static void d();
}
void HavingMutex::a()
{
boost::mutex::scoped_lock lock(m);
...
b() //Need to pass lock here. Dunno how !
}
void HavingMutex::b(lock)
{
if (some condition)
d(lock) // Need to pass lock here. How ?
}
void HavingMutex::d(//Need to get lock here)
{
c->wait(lock); //Need to pass lock here (doesn't allow direct passing of mutex m)
}
Basically, in function d(), I need to access the scoped lock I acquired in a() so that I can wait on it. How do I do that ? (Some other thread will notify).
Or can I directly wait on a mutex instead of a lock ?
Any help is appreciated. Thanks !
Pass it by reference:
void HavingMutex::d(boost::mutex::scoped_lock & lock)
{ // ^ that means "reference"
c->wait(lock);
}
I cannot use boost or the latest std::thread library. The way to go is to create a custom implementation of a scoped mutex.
In a few words when a class instance is create a mutex locks. Upon class destruction the mutex is unlocked.
Any implementation available? I don't want to re-invent the wheel.
I need to use pthreads.
resource acquisition is initialization == “RAII”
Note This is an old answer. C++11 contains better helpers that are more platform independent:
std::lock_guard
std::mutex, std::timed_mutex, std::recursive_mutex, std::recursive_timed_mutex
And other options like std::unique_lock, boost::unique_lock
Any RAII tutorial will do.
Here's the gist: (also on http://ideone.com/kkB86)
// stub mutex_t: implement this for your operating system
struct mutex_t
{
void Acquire() {}
void Release() {}
};
struct LockGuard
{
LockGuard(mutex_t& mutex) : _ref(mutex)
{
_ref.Acquire(); // TODO operating system specific
}
~LockGuard()
{
_ref.Release(); // TODO operating system specific
}
private:
LockGuard(const LockGuard&); // or use c++0x ` = delete`
mutex_t& _ref;
};
int main()
{
mutex_t mtx;
{
LockGuard lock(mtx);
// LockGuard copy(lock); // ERROR: constructor private
// lock = LockGuard(mtx);// ERROR: no default assignment operator
}
}
Of course you can make it generic towards mutex_t, you could prevent subclassing.
Copying/assignment is already prohibited because of the reference field
EDIT For pthreads:
struct mutex_t
{
public:
mutex_t(pthread_mutex_t &lock) : m_mutex(lock) {}
void Acquire() { pthread_mutex_lock(&m_mutex); }
void Release() { pthread_mutex_unlock(&m_mutex); }
private:
pthread_mutex_t& m_mutex;
};