I have a program with multiple resources that needs to be lock by their own mutex.
In this program, it might happen that while mutex for resource A is locked, resource A is deleted in another thread.
The following code try to reproduce the logic of what I try to accomplish :
#include <thread>
#include <mutex>
#include <iostream>
#include <map>
int g_i = 0;
struct Resource
{
std::mutex* m_mutex;
};
std::map<unsigned int, Resource> myResources;
std::mutex g_i_mutex; // protects g_i
void shutdown()
{
std::cout << "shutdown -> myMap.size = : " << myResources.size() << std::endl;
std::lock_guard<std::mutex> lock(*myResources[1].m_mutex);
++g_i;
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
delete myResources[1].m_mutex;
myResources[1].m_mutex = NULL;
myResources.erase(1);
std::cout << "shutdown -> myMap.size = : " << myResources.size() << std::endl;
std::cout << "shutdown : " << g_i << '\n';
}
void onRecognize()
{
std::cout << "onRecognize -> myMap.size = : " << myResources.size() << std::endl;
std::lock_guard<std::mutex> lock(*myResources[1].m_mutex);
std::cout << "onRecognize -> myMap.size = : " << myResources.size() << std::endl;
++g_i;
std::cout << "onRecognize : " << g_i << '\n';
}
int main()
{
std::cout << __func__ << ": " << g_i << '\n';
Resource myStruct;
myStruct.m_mutex = new std::mutex();
myResources[1] = myStruct;
std::thread t1(shutdown);
std::thread t2(onRecognize);
t1.join();
std::this_thread::sleep_for(std::chrono::milliseconds(500));
t2.join();
std::cout << __func__ << ": " << g_i << '\n';
}
I tried this snippet of code and it works. But I am wondering what happen with lock_guard in onRecognize function, because the mutex is being deleted while he is locked. So, my question might be :
Does deleting a mutex while he is locked somewhere else is dangerous?
Thx
Don't destroy a mutex while it is locked.
The behavior is undefined if the mutex is owned by any thread or if any thread terminates while holding any ownership of the mutex.
http://en.cppreference.com/w/cpp/thread/mutex/~mutex
You have a fundamental concurrency error that renders your code unreliable. The pointer m_mutex is modified in one thread and used in another, and no synchronization of any kind protects it.
This is catastrophic even if you can't imagine a way it can fail. But it happens to be very easy to imagine ways it can fail. Consider:
onRecognize evaluates *myResources[1].m_mutex but hasn't constructed the lock guard yet.
shutdown acquires the lock, destroys the mutex, and returns.
onRecognize tries to construct the lock guard on a lock that no longer exists.
Boom.
So you have bigger problems than anything specific to the semantics of mutexes.
GCC(10.2) & Clang(10) don't have issues with deleting a locked mutex, MSVC 19.28 will terminate.
{
std::mutex m;
m.lock();
}//std::terminate() - MSVC
Related
According to several documentation examples the thread can't unlock a mutex unless it locked it explicitly. Here is an excerpt from man page for pthread_mutex_unlock at IBM.
The pthread_mutex_unlock() function unlocks the mutex specified. If
the calling thread does not currently hold the mutex (via a previous
call to pthread_mutex_lock(), pthread_mutex_trylock(), or
pthread_mutex_timedlock_np()) the unlock request fails with the EPERM
error.
Even the new C++ standard says something similar about the thread ownership, yet the following program was able to unlock a mutex locked on a different thread. On gcc & Linux systems the same behavior is seen both on pthread mutex as well as std::mutex (which I believe is implemented based on pthread_mutex anyway).
#include <iostream>
#include <thread>
#include <mutex>
#include <pthread.h>
std::mutex stmutex;
pthread_mutex_t pthrmutex = PTHREAD_MUTEX_INITIALIZER;
void thread1(int i)
{
stmutex.unlock();
std::cout << "Un Locked in thread 1" << std::this_thread::get_id() << std::endl;
}
void pthread1(int i)
{
pthread_mutex_unlock(&pthrmutex);
std::cout << "Un Locked Pthread mutex in thread 1" << std::this_thread::get_id() << std::endl;
}
void thread2(int i)
{
stmutex.lock();
std::cout << "Locked in thread 2" << std::this_thread::get_id() << std::endl;
}
void thread3(int i)
{
stmutex.unlock();
std::cout << "UNLocked in thread 3" << std::this_thread::get_id() << std::endl;
}
int main(int argc, char **argv)
{
try {
stmutex.lock();
std::cout << "Locked in main thread : " << std::this_thread::get_id() << std::endl;
std::thread t1(thread1,1);
t1.join();
stmutex.lock();
std::cout << "Locked in main thread after unlocking in thread1" << std::endl;
stmutex.unlock();
std::cout << "Un Locked in main thread " << std::endl;
pthread_mutex_lock(&pthrmutex);
std::cout << "Locked pthread mutex in main thread : " << std::this_thread::get_id() << std::endl;
std::thread t2(pthread1,1);
t2.join();
pthread_mutex_lock(&pthrmutex);
std::cout << "Locked Pthread mutext in main thread after unlocking in thread1" << std::endl;
pthread_mutex_unlock(&pthrmutex);
std::cout << "Un Locked Pthread mutext in main thread " << std::endl;
std::thread t3(thread2,1);
t3.join();
std::thread t4(thread3,1);
t4.join();
} catch (std::exception& ex)
{
std::cerr << "Exception In main thread: " << ex.what() << std::endl;
}
}
Am I missing anything in my understanding of mutex "Ownership" ?
The request fails with the EPERM error only for mutexes created with PTHREAD_MUTEX_ERRORCHECK.
See pthread_mutex_lock section RATIONALE:
... while being able to extract the thread ID of the owner of a mutex might be desirable, it would require storing the current thread ID when each mutex is locked, and this could incur unacceptable levels of overhead.
I.e. initialize your mutex with PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP.
Example:
void locker(pthread_mutex_t* mutex) {
if(int e = pthread_mutex_lock(mutex))
fprintf(stderr, "pthread_mutex_lock: (%d)%s\n", e, strerror(e));
}
void unlocker(pthread_mutex_t* mutex) {
if(int e = pthread_mutex_unlock(mutex))
fprintf(stderr, "pthread_mutex_unlock: (%d)%s\n", e, strerror(e));
}
int main() {
pthread_mutex_t a = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t b = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
std::thread(locker, &a).join();
std::thread(locker, &b).join();
std::thread(unlocker, &a).join();
std::thread(unlocker, &b).join(); // pthread_mutex_unlock: (1)Operation not permitted
}
I have a "watch thread" which checks whether other threads are running and calculates some data. If these threads end I want to finish my watch thread, too. How can I do it?
#include <iostream>
#include <thread>
using namespace std;
void f1() {
cout << "thread t1" << endl;
for (int i=0; i<1000; ++i) {
cout << "t1: " << i << endl;
}
}
void f2() {
cout << "thread t2" << endl;
while (T1_IS_RUNNING) {
cout << "t1 still running" << endl;
}
}
int main() {
thread t1(f1);
thread t2(f2);
t1.join();
t2.join();
return 0;
}
In the example above I need to implement T1_IS_RUNNING. Any ideas how to do it? My guess is to get number of running threads but I haven't found any related method in STL.
There is a How to check if a std::thread is still running? already, but I think they use too complicated solutions for my case. Isn't a simple thread counter (std::atomic) good enough?
You can just use a flag for it (running example):
#include <iostream>
#include <thread>
using namespace std;
bool T1_IS_RUNNING = true;
void f1() {
cout << "thread t1" << endl;
for (int i=0; i<1000; ++i) {
cout << "t1: " << i << endl;
}
T1_IS_RUNNING = false;
cout << "thread t1 finish" << endl;
}
void f2() {
cout << "thread t2" << endl;
while (T1_IS_RUNNING) {
cout << "t1 still running" << endl;
}
cout << "thread t2 finish" << endl;
}
int main() {
thread t1(f1);
thread t2(f2);
t1.join();
t2.join();
return 0;
}
This is safe as long as only one of them writes the flag and the other reads it, otherwise you need to use an atomic flag, a mutex or a semaphore.
With atomic_int:
int main(){
std::atomic_int poor_man_semaphore{0};
poor_man_semaphore++;
std::thread t1([&]()
{
std::this_thread::sleep_for(std::chrono::seconds(100));
poor_man_semaphore--;
});
poor_man_semaphore++;
std::thread t2([&]()
{
std::this_thread::sleep_for(std::chrono::seconds(1));
poor_man_semaphore--;
});
poor_man_semaphore++;
std::thread t3([&]()
{
std::this_thread::sleep_for(std::chrono::seconds(1));
poor_man_semaphore--;
});
t2.join();
t3.join();
while ( poor_man_semaphore > 0 )
{
std::this_thread::sleep_for(std::chrono::seconds(1));
}
t1.join();
return 0;
}
Let me give a quick fix to the code, as there is already a detailed post, this will not be long.
This answer exists because there are many wrong answers here.
My interpretation of your problem is you want a "watch thread" to do work while other threads are still alive, but stop whenever others stop.
#include <fstream>
#include <thread>
#include <atomic> // this is REQUIRED, NOT OPTIONAL
using namespace std;
atomic_int count(1); // REQUIRED to be atomic
void f1() {
ofstream f1out{"f1out.txt"};
f1out << "thread t1" << endl;
for (int i=0; i<1000; ++i) {
f1out << "t1: " << i << endl;
}
count--;
}
void f2() {
ofstream f2out{"f2out.txt"};
f2out << "thread t2" << endl;
while (count > 0) {
f2out << "t1 still running" << endl;
}
}
int main() {
thread t1(f1);
thread t2(f2);
t1.join();
t2.join();
}
Notes on atomic
The syntax of atomic_int might look like an int but they are different and failing to use atomic_int is undefined behaviour.
From [intro.races], emphasis mine
Two expression evaluations conflict if one of them modifies a memory location and the other one reads or modifies the same memory location. [...]
The execution of a program contains a data race if it contains two potentially concurrent conflicting actions, at least one of which is not atomic, and neither happens before the other [...] . Any such data race results in undefined behavior.
Notes on cout
Likewise, it is a data race if the threads use cout concurrently, I can't find a simple replacement to preserve the meaning and effect. I opt into using ofstream in the end.
For people concerned
Yes, the atomic operations need not be sequentially consistent but that really doesn't help with clarity.
This link might help you.
Amongst a lot of solutions, one seems quite easy to implement :
An easy solution is to have a boolean variable that the thread sets to true on regular intervals, and that is checked and set to false by the thread wanting to know the status. If the variable is false for to long then the thread is no longer considered active.
A more thread-safe way is to have a counter that is increased by the child thread, and the main thread compares the counter to a stored value and if the same after too long time then the child thread is considered not active.
May be you could set an array of boolean, one by thread you run, and then check it whenever you want to know if other threads are running ?
I'm using boost 1.54.0 and Visual Studio 2010. For the code:
#include <iostream>
#include "boost/thread/thread.hpp"
#include "boost/thread/mutex.hpp"
boost::mutex mx1;
void func1()
{
{
boost::mutex::scoped_lock(mx1);
std::cout << "Thread " << boost::this_thread::get_id() << " starting work." << std::endl;
}
int x = 0;
for (int i=0; i<100; i++)
x++;
{
boost::mutex::scoped_lock(mx1);
std::cout << "Thread " << boost::this_thread::get_id() << " finished." << std::endl;
}
}
int main(void)
{
boost::thread thread1(&func1);
boost::thread thread2(&func1);
thread1.join();
thread2.join();
return 0;
}
About half the time I get the following (with varying thread ids and execution order, obviously):
Thread Thread 15b0 starting work.
1a18 starting work.
Thread 15b0 finished.
Thread 1a18 finished.
...instead of this (which is what I'd expect):
Thread 15b0 starting work.
Thread 1a18 starting work.
Thread 15b0 finished.
Thread 1a18 finished.
However, using
mx1.lock();
std::cout << "Thread " << boost::this_thread::get_id() << " starting work." << std::endl;
mx1.unlock();
...seems to work with no problems.
The output always seems to follow the same pattern. Am I using the mutex incorrectly, or is it something to do with std::cout?
Replace
boost::mutex::scoped_lock(mx1);
with
boost::mutex::scoped_lock lock(mx1);
you fell a victim of the most frequently occurring typo with the scoped lock:-)
I have a multithreaded c++ application. I want to flag an object with a busy/free state, such as:
Threads can toggle the object's state
Threads must have exclusive access to certain public member functions at any time (while other public member functions don't need synchronization)
If the object is busy, a thread can choose to wait either infinitely or for a defined period until the object becomes free.
I implemented the requirements below, is there a better way to do it?
#include <condition_variable>
#include <mutex>
#include <atomic>
#include <thread>
#include <iostream>
std::mutex m_Mutex;
std::condition_variable m_ConditionVariable;
std::atomic_flag m_BusyFlag;
const int TRY_LOCK_TIMEOUT_MILLIS = 1;
bool IsFree() { return !m_BusyFlag.test_and_set(); }
bool LockSeqNum(bool timed_wait)
{
std::cout <<" TRY LockSeqNum, thread= " << std::this_thread::get_id() << endl;
bool success = true;
std::unique_lock<std::mutex> lck(m_Mutex);
if (m_BusyFlag.test_and_set())
{
if (timed_wait)
success = !m_ConditionVariable.wait_for(lck, std::chrono::milliseconds(TRY_LOCK_TIMEOUT_MILLIS), [] { return IsFree(); });
else
m_ConditionVariable.wait(lck, [] { return IsFree(); });
}
std::cout << "LockSeqNum " << success << " thread = " << std::this_thread::get_id() << endl;
return success;
}
void UnlockSeqNum()
{
std::cout << " UNLockSeqNum, thread= " << std::this_thread::get_id() << endl;
std::unique_lock<std::mutex> lck(m_Mutex);
m_BusyFlag.clear();
m_ConditionVariable.notify_one();
}
If you want to allow outer of IsFree(), code is fine. Otherwise, as Yakk pointed in comments, it is sufficient to declare m_BusyFlag as simple boolean. atomic_flag is overhead there as variable is always accessed under the mutex.
You have the minimal tools, needed for use conditional wait: conditional variable, mutex and normal variable for wait its state. So, the simpler implementation(simple locking) is possible only if UnlockSeqNum is required to be called by the thread, which have called LockSeqNum before.
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
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.
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
A deadlock requires TWO mutexes to be acquired in different orders in different threads. I only see a single mutex in your code.