Was trying to execute a piece of code only when mutex is locked. Methods in class mainclass does the task only when the mutex is locked. To avoid creating undefined behaviour when the mutex is unlocked without locking ( considering case where locking may fail), lock and unlock is handled with constructor and destructor of mutexclass.
I want to check if mutex is locked before executing the code from mainclass methods calling1() and calling2(). As constructor won't return values, want to know alternate methods of doing this.
#include <iostream>
using namespace std;
class mutexclass
{
public:
pthread_mutex_t *mutex;
bool a = true;
mutexclass(pthread_mutex_t* inmutex)
{ mutex= inmutex;
int err=pthread_mutex_lock(mutex);
cout<<"automutex constructor";
if(err != 0)
a = false;
};
~mutexclass()
{
if(a)
{
pthread_mutex_unlock(mutex);
cout<<"automutex destructor";
}
else
cout<<"a is not true";
};
};
class mainclass{
public:
mainclass();
~mainclass();
pthread_mutex_t lock;
void calling1();
void calling2();
};
mainclass::mainclass()
{
pthread_mutex_init(&lock,NULL);
}
mainclass::~mainclass()
{
pthread_mutex_destroy(&lock);
}
void mainclass::calling1()
{
mutexclass m = mutexclass(&lock);
//call cout only if mutex lock is successful
cout<<"calling1";
}
void mainclass::calling2()
{
mutexclass m = mutexclass(&lock);
cout<<"calling2";
}
int main() {
mainclass s;
s.calling1();
s.calling2();
return 0;
}
You should really use std::mutex and std::lock_guard, and in general the standard C++ threading support. But if for some reason you can't (maybe this is a learning exercise?) then I recommend preventing mutexclass from ever being in a state where the mutex is not locked. That should be an error, so throw an exception if the lock can't be acquired.
It's also important to prevent instances from being copied. Otherwise, the same mutex will be unlocked multiple times in the destructor of each copy. To prevent that, delete the copy constructor and assignment operator.
#include <system_error>
class mutexclass
{
public:
explicit mutexclass(pthread_mutex_t* inmutex)
: mutex(inmutex)
{
int err = pthread_mutex_lock(mutex);
if (err != 0) {
throw std::system_error(err, std::generic_category(),
"pthread mutex lock acquisition failure");
}
}
~mutexclass()
{
pthread_mutex_unlock(mutex);
}
mutexclass(const mutexclass&) = delete;
mutexclass& operator=(const mutexclass&) = delete;
private:
pthread_mutex_t* mutex;
};
Now you can implement the calling* functions like this:
void mainclass::calling1()
{
try {
mutexclass m(&lock);
cout << "calling1\n";
} catch (const std::exception& e) {
// Could not lock.
}
}
You set a boolean to indicate whether the mutex is locked or not. You can also check that value outside the class:
class mutexclass
{
public:
mutexclass(pthread_mutex_t* inmutex)
{
mutex = inmutex;
int err = pthread_mutex_lock(mutex);
if(err == 0) locked_ = true;
}
~mutexclass()
{
if(locked_) {
pthread_mutex_unlock(mutex);
}
}
bool locked() const { return locked_; }
private:
pthread_mutex_t *mutex;
bool locked_ = false;
};
void mainclass::calling1()
{
mutexclass m = mutexclass(&lock);
//call cout only if mutex lock is successful
if (m.locked()) {
cout<<"calling1";
}
}
You could also use std::mutex, which throws an exception on errors.
I'm new to C++11 threading and I'm trying to do something as follows:
class Something {
public:
void start() {
this->task_ = std::thread(&Something::someTask, this);
this->isRunning_ = true;
this->task_.detach(); // I read detach will stop it from hanging
}
void stop() {
this->isRunning = false;
}
~Something() {
this->stop();
}
private:
std::atomic<bool> isRunning_;
std::thread task_;
void someTask()
{
while(this->isRunning_) {
// do something forever
}
}
};
Something whatever;
whatever.start();
However, the thread keeps getting blocked. Like nothing after whatever.start() executes. It just hangs while the loop runs.
The usual pattern to do this is
class Something {
public:
void start() {
this->task_ = std::thread(&Something::someTask, this);
// this->task_.detach(); <<<<<< Don't do that.
}
void stop() {
this->isRunning_ = false;
task_.join(); // <<< Instead of detaching the thread, join() it.
}
~Something() {
this->stop();
}
private:
std::atomic<bool> isRunning_;
std::thread task_;
void someTask()
{
this->isRunning_ = true;
while(this->isRunning_) {
// do something forever
}
}
};
Detaching a std::thread usually isn't a good idea, unless there's some kind of synchronization set up, that allows to wait for the thread execution to end before the process ends as a whole.
Demonizing a process usually is realized with a fork() to create a background child process, and leave the parent process to return control to the caller.
I recently wrote a generic class that does just this
#include<functional>
#include<thread>
//do action asynchronously until condition is false
class do_async_until{
public:
do_async_until(std::function<void(void)> action,
std::function<bool(void)> condition);
~do_async_until();
void start();
void stop();
private:
void _do();
std::thread _worker;
std::function<void(void)> _action;
std::function<bool(void)> _condition;
};
//implementation
do_async_until::do_async_until(std::function<void(void)> action,
std::function<bool(void)> condition):_action(action),
_condition(condition){
}
do_async_until::~do_async_until(){
stop();
}
void do_async_until::start(){
_worker = std::thread(std::bind(&do_async_until::_do,this));
}
void do_async_until::stop(){
if(_worker.joinable()){
_worker.join();
}
}
void do_async_until::_do(){
while (_condition())
{
_action();
}
}
this will run any function with the signiture void(void) until the condition function bool(void) returns true
example usage:
int main(int agrc,char** argv){
bool running = true;
auto do_this = [](){
std::cout<<"hello world"<<std::endl;
};
auto condition = [&](){
return running;
};
do_async_until async(do_this,condition);
async.start();
std::this_thread::sleep_for(std::chrono::seconds(1));
running=false;
return 0;
}
The example should print "hello world" a bunch of times for one seconds then exit.
EDIT: to make this work with a member function you simply need to have an instance of do_async_until inside you class and pass the member function to the constructor of do_async_until using std::bind(&foo::func,this)
There is a shared_mutex class planned for C++17. And shared_timed_mutex already in C++14. (Who knows why they came in that order, but whatever.) Then there is a recursive_mutex and a recursive_timed_mutex since C++11. What I need is a shared_recursive_mutex. Did I miss something in the standard or do I have to wait another three years for a standardized version of that?
If there is currently no such facility, what would be a simple (first priority) and efficient (2nd priority) implementation of such a feature using standard C++ only?
Recursive property of the mutex operates with the term "owner", which in case of a shared_mutex is not well-defined: several threads may have .lock_shared() called at the same time.
Assuming "owner" to be a thread which calls .lock() (not .lock_shared()!), an implementation of the recursive shared mutex can be simply derived from shared_mutex:
class shared_recursive_mutex: public shared_mutex
{
public:
void lock(void) {
std::thread::id this_id = std::this_thread::get_id();
if(owner == this_id) {
// recursive locking
count++;
}
else {
// normal locking
shared_mutex::lock();
owner = this_id;
count = 1;
}
}
void unlock(void) {
if(count > 1) {
// recursive unlocking
count--;
}
else {
// normal unlocking
owner = std::thread::id();
count = 0;
shared_mutex::unlock();
}
}
private:
std::atomic<std::thread::id> owner;
int count;
};
The field .owner needs to be declared as atomic, because in the .lock() method this field is checked without a protection from the concurrent access.
If you want to recursively call .lock_shared() method, you need to maintain a map of owners, and accesses to that map should be protected with some additional mutex.
Allowing a thread with active .lock() to call .lock_shared() makes implementation to be more complex.
Finally, allowing a thread to advance locking from .lock_shared() to .lock() is no-no, as it leads to possible deadlock when two threads attempt to perform that advancing.
Again, semantic of recursive shared mutex would be very fragile, so it is better to not use it at all.
If you are on Linux / POSIX platform, you are in luck because C++ mutexes are modelled after POSIX ones. The POSIX ones provide more features, including being recursive, process shared and more. And wrapping POSIX primitives into C++ classes is straight-forward.
Good entry point into POSIX threads documentation.
Here is a quick thread-safety wrapper around a type T:
template<class T, class Lock>
struct lock_guarded {
Lock l;
T* t;
T* operator->()&&{ return t; }
template<class Arg>
auto operator[](Arg&&arg)&&
-> decltype(std::declval<T&>()[std::declval<Arg>()])
{
return (*t)[std::forward<Arg>(arg)];
}
T& operator*()&&{ return *t; }
};
constexpr struct emplace_t {} emplace {};
template<class T>
struct mutex_guarded {
lock_guarded<T, std::unique_lock<std::mutex>>
get_locked() {
return {{m},&t};
}
lock_guarded<T const, std::unique_lock<std::mutex>>
get_locked() const {
return {{m},&t};
}
lock_guarded<T, std::unique_lock<std::mutex>>
operator->() {
return get_locked();
}
lock_guarded<T const, std::unique_lock<std::mutex>>
operator->() const {
return get_locked();
}
template<class F>
std::result_of_t<F(T&)>
operator->*(F&& f) {
return std::forward<F>(f)(*get_locked());
}
template<class F>
std::result_of_t<F(T const&)>
operator->*(F&& f) const {
return std::forward<F>(f)(*get_locked());
}
template<class...Args>
mutex_guarded(emplace_t, Args&&...args):
t(std::forward<Args>(args)...)
{}
mutex_guarded(mutex_guarded&& o):
t( std::move(*o.get_locked()) )
{}
mutex_guarded(mutex_guarded const& o):
t( *o.get_locked() )
{}
mutex_guarded() = default;
~mutex_guarded() = default;
mutex_guarded& operator=(mutex_guarded&& o)
{
T tmp = std::move(o.get_locked());
*get_locked() = std::move(tmp);
return *this;
}
mutex_guarded& operator=(mutex_guarded const& o):
{
T tmp = o.get_locked();
*get_locked() = std::move(tmp);
return *this;
}
private:
std::mutex m;
T t;
};
You can use either:
mutex_guarded<std::vector<int>> guarded;
auto s0 = guarded->size();
auto s1 = guarded->*[](auto&&e){return e.size();};
both do roughly the same thing, and the object guarded is only accessed when the mutex is locked.
Stealing from #tsyvarev 's answer (with some minor changes) we get:
class shared_recursive_mutex
{
std::shared_mutex m
public:
void lock(void) {
std::thread::id this_id = std::this_thread::get_id();
if(owner == this_id) {
// recursive locking
++count;
} else {
// normal locking
m.lock();
owner = this_id;
count = 1;
}
}
void unlock(void) {
if(count > 1) {
// recursive unlocking
count--;
} else {
// normal unlocking
owner = std::thread::id();
count = 0;
m.unlock();
}
}
void lock_shared() {
std::thread::id this_id = std::this_thread::get_id();
if (shared_counts->count(this_id)) {
++(shared_count.get_locked()[this_id]);
} else {
m.lock_shared();
shared_count.get_locked()[this_id] = 1;
}
}
void unlock_shared() {
std::thread::id this_id = std::this_thread::get_id();
auto it = shared_count->find(this_id);
if (it->second > 1) {
--(it->second);
} else {
shared_count->erase(it);
m.unlock_shared();
}
}
private:
std::atomic<std::thread::id> owner;
std::atomic<std::size_t> count;
mutex_guarded<std::map<std::thread::id, std::size_t>> shared_counts;
};
try_lock and try_lock_shared left as an exercise.
Both lock and unlock shared lock the mutex twice (this is safe, as the branches are really about "is this thread in control of the mutex", and another thread cannot change that answer from "no" to "yes" or vice versa). You could do it with one lock with ->* instead of ->, which would make it faster (at the cost of some complexity in the logic).
The above does not support having an exclusive lock, then a shared lock. That is tricky. It cannot support having a shared lock, then upgrading to an unique lock, because that is basically impossible to stop it from deadlocking when 2 threads try that.
That last issue may be why recursive shared mutexes are a bad idea.
It is possible to construct a shared recursive mutex using existing primitives. I don't recommend doing it, though.
It isn't simple, and wrapping the existing POSIX implementation (or whatever is native to your platform) is very likely to be more efficient.
If you do decide to write your own implementation, making it efficient still depends on platform-specific details, so you're either writing an interface with a different implementation for each platform, or you're selecting a platform and could just as easily use the native (POSIX or whatever) facilities instead.
I'm certainly not going to provide a sample recursive read/write lock implementation, because it's a wholly unreasonable amount of work for an Stack Overflow answer.
Sharing my implementation, no promises
recursive_shared_mutex.h
#ifndef _RECURSIVE_SHARED_MUTEX_H
#define _RECURSIVE_SHARED_MUTEX_H
#include <thread>
#include <mutex>
#include <map>
struct recursive_shared_mutex
{
public:
recursive_shared_mutex() :
m_mtx{}, m_exclusive_thread_id{}, m_exclusive_count{ 0 }, m_shared_locks{}
{}
void lock();
bool try_lock();
void unlock();
void lock_shared();
bool try_lock_shared();
void unlock_shared();
recursive_shared_mutex(const recursive_shared_mutex&) = delete;
recursive_shared_mutex& operator=(const recursive_shared_mutex&) = delete;
private:
inline bool is_exclusive_locked()
{
return m_exclusive_count > 0;
}
inline bool is_shared_locked()
{
return m_shared_locks.size() > 0;
}
inline bool can_exclusively_lock()
{
return can_start_exclusive_lock() || can_increment_exclusive_lock();
}
inline bool can_start_exclusive_lock()
{
return !is_exclusive_locked() && (!is_shared_locked() || is_shared_locked_only_on_this_thread());
}
inline bool can_increment_exclusive_lock()
{
return is_exclusive_locked_on_this_thread();
}
inline bool can_lock_shared()
{
return !is_exclusive_locked() || is_exclusive_locked_on_this_thread();
}
inline bool is_shared_locked_only_on_this_thread()
{
return is_shared_locked_only_on_thread(std::this_thread::get_id());
}
inline bool is_shared_locked_only_on_thread(std::thread::id id)
{
return m_shared_locks.size() == 1 && m_shared_locks.find(id) != m_shared_locks.end();
}
inline bool is_exclusive_locked_on_this_thread()
{
return is_exclusive_locked_on_thread(std::this_thread::get_id());
}
inline bool is_exclusive_locked_on_thread(std::thread::id id)
{
return m_exclusive_count > 0 && m_exclusive_thread_id == id;
}
inline void start_exclusive_lock()
{
m_exclusive_thread_id = std::this_thread::get_id();
m_exclusive_count++;
}
inline void increment_exclusive_lock()
{
m_exclusive_count++;
}
inline void decrement_exclusive_lock()
{
if (m_exclusive_count == 0)
{
throw std::logic_error("Not exclusively locked, cannot exclusively unlock");
}
if (m_exclusive_thread_id == std::this_thread::get_id())
{
m_exclusive_count--;
}
else
{
throw std::logic_error("Calling exclusively unlock from the wrong thread");
}
}
inline void increment_shared_lock()
{
increment_shared_lock(std::this_thread::get_id());
}
inline void increment_shared_lock(std::thread::id id)
{
if (m_shared_locks.find(id) == m_shared_locks.end())
{
m_shared_locks[id] = 1;
}
else
{
m_shared_locks[id] += 1;
}
}
inline void decrement_shared_lock()
{
decrement_shared_lock(std::this_thread::get_id());
}
inline void decrement_shared_lock(std::thread::id id)
{
if (m_shared_locks.size() == 0)
{
throw std::logic_error("Not shared locked, cannot shared unlock");
}
if (m_shared_locks.find(id) == m_shared_locks.end())
{
throw std::logic_error("Calling shared unlock from the wrong thread");
}
else
{
if (m_shared_locks[id] == 1)
{
m_shared_locks.erase(id);
}
else
{
m_shared_locks[id] -= 1;
}
}
}
std::mutex m_mtx;
std::thread::id m_exclusive_thread_id;
size_t m_exclusive_count;
std::map<std::thread::id, size_t> m_shared_locks;
std::condition_variable m_cond_var;
};
#endif
recursive_shared_mutex.cpp
#include "recursive_shared_mutex.h"
#include <condition_variable>
void recursive_shared_mutex::lock()
{
std::unique_lock sync_lock(m_mtx);
m_cond_var.wait(sync_lock, [this] { return can_exclusively_lock(); });
if (is_exclusive_locked_on_this_thread())
{
increment_exclusive_lock();
}
else
{
start_exclusive_lock();
}
}
bool recursive_shared_mutex::try_lock()
{
std::unique_lock sync_lock(m_mtx);
if (can_increment_exclusive_lock())
{
increment_exclusive_lock();
return true;
}
if (can_start_exclusive_lock())
{
start_exclusive_lock();
return true;
}
return false;
}
void recursive_shared_mutex::unlock()
{
{
std::unique_lock sync_lock(m_mtx);
decrement_exclusive_lock();
}
m_cond_var.notify_all();
}
void recursive_shared_mutex::lock_shared()
{
std::unique_lock sync_lock(m_mtx);
m_cond_var.wait(sync_lock, [this] { return can_lock_shared(); });
increment_shared_lock();
}
bool recursive_shared_mutex::try_lock_shared()
{
std::unique_lock sync_lock(m_mtx);
if (can_lock_shared())
{
increment_shared_lock();
return true;
}
return false;
}
void recursive_shared_mutex::unlock_shared()
{
{
std::unique_lock sync_lock(m_mtx);
decrement_shared_lock();
}
m_cond_var.notify_all();
}
If a thread owns a shared lock, it may also obtain an exclusive lock without giving up it's shared lock. (This of course requires no other thread currently has a shared or exclusive lock)
Vice-versa, a thread which owns an exclusive lock may obtain a shared lock.
Interestingly, these properties also allow locks to be upgradable/downgradable.
Temporarily upgrading lock:
recusrive_shared_mutex mtx;
foo bar;
mtx.lock_shared();
if (bar.read() == x)
{
mtx.lock();
bar.write(y);
mtx.unlock();
}
mtx.unlock_shared();
Downgrading from an exclusive lock to a shared lock
recusrive_shared_mutex mtx;
foo bar;
mtx.lock();
bar.write(x);
mtx.lock_shared();
mtx.unlock();
while (bar.read() != y)
{
// Something
}
mtx.unlock_shared();
I searched for a C++ read-write-lock and came across this related question. We did need exactly such a shared_recursive_mutex to control access to our "database" class from multiple threads. So, for completeness: If you are looking for another implementation example (like I was), you may want to consider this link too: shared_recursive_mutex implementation using C++17 (on github).
Features
C++17
Single Header
Dependency-free
It has a disadvantage though: static thread_local members specialized for a PhantomType class via template. So, you can't really use this shared_recursive_mutex in multiple separate instances of the same (PhantomType) class. Try it, if that is no restriction for you.
The following implementation supports first having a unique_lock and then acquiring an additional shared_lock in the same thread:
#include <shared_mutex>
#include <thread>
class recursive_shared_mutex: public std::shared_mutex {
public:
void lock() {
if (owner_ != std::this_thread::get_id()) {
std::shared_mutex::lock();
owner_ = std::this_thread::get_id();
}
++count_;
}
void unlock() {
--count_;
if (count_ == 0) {
owner_ = std::thread::id();
std::shared_mutex::unlock();
}
}
void lock_shared() {
if (owner_ != std::this_thread::get_id()) {
std::shared_mutex::lock_shared();
}
}
void unlock_shared() {
if (owner_ != std::this_thread::get_id()) {
std::shared_mutex::unlock_shared();
}
}
private:
std::atomic<std::thread::id> owner_;
std::atomic_uint32_t count_ = 0;
};
Okay this meight be a bit off for Stack but ill try to keep it as short as possible.
I got thread which takes tasks out of a list and executes them. Simple as this (The worker class has its own thread and runs doTask m_thread(&Worker::doTask, this)):
void Worker::doTask()
{
while (m_running)
{
auto task = m_tasks.pop_front();
task->execute();
if (task->isContinuous())
m_tasks.push_pack(task);
}
}
The list itself is/should be threadsafe:
Header:
class TaskQueue
{
public:
void push_pack(std::shared_ptr<Task> t);
std::shared_ptr<Task> pop_front();
private:
std::list<std::shared_ptr<Task>> m_tasks;
std::condition_variable m_cond;
std::mutex m_mutex;
void TaskQueue::push_pack(std::shared_ptr<Task> t)
}
Impls of the importand part:
void TaskQueue::push_pack(std::shared_ptr<Task> t)
{
m_tasks.push_back(t);
//notify that there is one more task, so one thread can work now
m_cond.notify_one();
}
std::shared_ptr<Task> TaskQueue::pop_front()
{
//regular lock so noone else acces this area now
std::unique_lock<std::mutex> lock(m_mutex);
while (m_tasks.size() == 0)
m_cond.wait(lock);
auto task = m_tasks.front();
m_tasks.pop_front();
return task;
}
last but not least the tasks:
class Task
{
public:
virtual ~Task()
{
}
virtual void execute() = 0;
virtual bool isContinuous()
{
return false;
};
};
So if i try to add this Task:
class NetworkRequestTask:public Task
{
public:
NetworkRequestTask(TaskQueue &q);
~NetworkRequestTask();
void execute() override;
bool isContinuous() override;
private:
TaskQueue &m_tasks;
};
Impl:
NetworkRequestTask::NetworkRequestTask(TaskQueue& q): m_tasks(q)
{
}
NetworkRequestTask::~NetworkRequestTask()
{
}
void NetworkRequestTask::execute()
{
while(dosomething)
{
//do something here
}
}
bool NetworkRequestTask::isContinuous()
{
return true;
}
Main:
int main(int argc, char* argv[])
{
TaskQueue tasks;
tasks.push_pack(std::make_shared<NetworkRequestTask>(tasks));
}
it gets into a bad state:
Expression: list iterator not derefercable
I am Confused. This only happens if i override continouse and this only happens at this task. If i add the queue to a other continouse task as reference it does not get into that bad state.
So whats going wrong here and more importand what have i done wrong?
As from the comments, i already tried to lock the push_back method which did not change anything to the behaviour. (You can exchange it for a regular mutex it doesnt matter.)
void TaskQueue::push_pack(std::shared_ptr<Task> t)
{
std::lock_guard<SpinLock> lock(m_spin);
m_tasks.push_back(t);
//notify that there is one more task, so one thread can work now
m_cond.notify_one();
}
I have a windows server application that uses multiple threads to handle requests. I needed a reader-writer lock to guard access to a shared std::unordered_map; and I wanted to do this in a manner similar to a std::unique_lock (resource acquisition is initialization). So I came up with this SRWRaii class.
class SRWRaii
{
public:
SRWRaii(const SRWLOCK& lock, bool m_exclusive = false)
:m_lock(lock), m_exclusive(m_exclusive)
{
if (m_exclusive)
{
AcquireSRWLockExclusive(const_cast<SRWLOCK*>(&m_lock));
}
else
{
AcquireSRWLockShared(const_cast<SRWLOCK*>(&m_lock));
}
}
~SRWRaii()
{
if (m_exclusive)
{
ReleaseSRWLockExclusive(const_cast<SRWLOCK*>(&m_lock));
}
else
{
ReleaseSRWLockShared(const_cast<SRWLOCK*>(&m_lock));
}
}
private:
const SRWLOCK& m_lock;
bool m_exclusive;
};
Then I use this as follows
SRWLOCK g_mutex;
void Initialize()
{
InitializeSRWLock(&g_mutex);
}
void Reader()
{
SRWRaii lock(g_mutex);
// Read from unordered_map
}
void Writer()
{
SRWRaii lock(g_mutex, true); // exclusive
// add or delete from unordered_map
}
Given my noviceness to c++, I am a little suspect of this critical code. Are there issues with the above approach of implementing an Raii wrapper over SRWLOCK? What improvements can be done to the above code?