Trying to expand in my two previous questions Move operations for a class with a thread as member variable and Call function inside a lambda passed to a thread
I'm not understanding why the thread doing a wait_for is somtimes not being notified wich results in a deadlock. Cppreference says on condition variables http://en.cppreference.com/w/cpp/thread/condition_variable/notify_one
The notifying thread does not need to hold the lock on the same mutex as the one held by the waiting thread(s); in fact doing so is a pessimization, since the notified thread would immediately block again, waiting for the notifying thread to release the lock.
MCVE, the commented line explains what changes if I hold the lock, but I dont undrestand why:
#include <atomic>
#include <condition_variable>
#include <mutex>
#include <thread>
#include <iostream>
using namespace std;
class worker {
public:
template <class Fn, class... Args>
explicit worker(Fn func, Args... args) {
t = std::thread(
[&func, this](Args... cargs) -> void {
std::unique_lock<std::mutex> lock(mtx);
while (true) {
cond.wait(lock, [this]() -> bool { return ready; });
if (terminate) {
break;
}
func(cargs...);
ready = false;
}
},
std::move(args)...);
}
~worker() {
terminate = true;
if (t.joinable()) {
run_once();
t.join();
}
}
void run_once() {
// If i dont hold this mutex the thread is never notified of ready being
// true.
std::unique_lock<std::mutex> lock(mtx);
ready = true;
cout << "ready run once " << ready << endl;
cond.notify_all();
}
bool done() { return (!ready.load()); }
private:
std::thread t;
std::atomic<bool> terminate{false};
std::atomic<bool> ready{false};
std::mutex mtx;
std::condition_variable cond;
};
// main.cpp
void foo() {
worker t([]() -> void { cout << "Bark" << endl; });
t.run_once();
while (!t.done()) {
}
}
int main() {
while (true) {
foo();
}
return 0;
}
You need a memory barrier to make sure that the other thread will see the modified "ready" value. "ready" being atomic only ensures that the memory access is ordered so that modifications that happened before the atomic access are actually flushed to main memory. This does not guarantee that the other threads will see that memory, since these threads may have their own cache of the memory. Therefore, to ensure that the other thread sees the "ready" modification, the mutex is required.
{
std::unique_lock<std::mutex> lock(mtx);
ready = true;
}
Related
I want to create a thread that can be interrupted while waiting (it waits data from other processes and I want to stop the process in nice way).
I've read the 9.2 part of C++ Concurrency in Action 2nd Edition, and I've tried to implement that ideas, but I've some problem and I don't know where to check.
This is my code based on that example:
#include <iostream>
#include <stdexcept>
#include <thread>
#include <mutex>
#include <atomic>
#include <condition_variable>
#include <future>
// Exception that should be raised when there's an interruption.
// It's raised when the thread is interrupted, so we can catch
// it and finish the thread execution.
class InterruptedException : public std::runtime_error {
public:
InterruptedException(const std::string& message) : std::runtime_error(message) {}
virtual ~InterruptedException() {}
};
// Interrupt flag. This class represents a local-thread flag that
// tells if the thread is interrupted or not.
class InterruptFlag {
public:
InterruptFlag() :
m_threadConditionVariable(nullptr),
m_threadConditionVariableAny(nullptr) {}
void set() {
m_flag.store(true, std::memory_order_relaxed);
std::lock_guard<std::mutex> lk(m_setClearMutex);
if (m_threadConditionVariable) {
m_threadConditionVariable->notify_all();
}
else if (m_threadConditionVariableAny) {
m_threadConditionVariableAny->notify_all();
}
}
template <typename Lockable>
void wait(std::condition_variable_any& cv, Lockable& lk) {
struct CustomLock {
InterruptFlag* m_self;
Lockable& m_lk;
CustomLock(InterruptFlag* self, std::condition_variable_any& cond, Lockable& lk) :
m_self(self),
m_lk(lk) {
m_self->m_setClearMutex.unlock();
m_self->m_threadConditionVariableAny = &cond;
}
void unlock() {
m_lk.unlock();
m_self->m_setClearMutex.unlock();
}
void lock() {
std::lock(m_self->m_setClearMutex, lk);
}
~CustomLock() {
m_self->m_threadConditionAny = nullptr;
m_self->m_setClearMutex.unlock();
}
};
CustomLock cl(this, cv, lk);
InterruptPoint();
cv.wait(cl);
InterruptPoint();
}
void setConditionVariable(std::condition_variable& cv) {
std::lock_guard<std::mutex> lk(m_setClearMutex);
m_threadConditionVariable = &cv;
}
void clearConditionVariable() {
std::lock_guard<std::mutex> lk(m_setClearMutex);
m_threadConditionVariable = nullptr;
}
bool isSet() const {
return m_flag.load(std::memory_order_relaxed);
}
private:
std::atomic<bool> m_flag;
std::condition_variable* m_threadConditionVariable;
std::condition_variable_any* m_threadConditionVariableAny;
std::mutex m_setClearMutex;
};
// Thread-local interrupt flag instance. The variable should be
// created for every thread, since it's thread_local.
thread_local InterruptFlag ThisThreadInterruptFlag;
// Convenience class for cleaning the flag due to RAII.
struct ClearConditionVariableOnDestruct {
~ClearConditionVariableOnDestruct() {
ThisThreadInterruptFlag.clearConditionVariable();
}
};
// Function that throws the exception that tells that the thread
// is interrupted. For doing it checks the state of ThisThreadInterruptFlag.
void InterruptionPoint() {
if (ThisThreadInterruptFlag.isSet()) {
throw InterruptedException("Interrupted");
}
}
// Function that must be used inside the thread function body for waiting.
// It waits for the condition variable, when it notifies from other threads,
// but it also notifies if the thread is interrupted.
void InterruptibleWait(std::condition_variable& cv, std::unique_lock<std::mutex>& lk) {
InterruptionPoint();
ThisThreadInterruptFlag.setConditionVariable(cv);
ClearConditionVariableOnDestruct guard;
InterruptionPoint();
cv.wait_for(lk, std::chrono::milliseconds(1));
InterruptionPoint();
}
// This class represents the interruptible thread. It adds a interrupt()
// method that when called interupts the thread execution, if it's waiting
// at some point where InterruptibleWait function is locked.
class Interruptible {
public:
template <typename FunctionType>
Interruptible(FunctionType f) {
std::promise<InterruptFlag*> p;
m_internalThread = std::thread([f, &p]() {
p.set_value(&ThisThreadInterruptFlag);
try {
f();
}
catch (InterruptedException) {
}
});
m_flag = p.get_future().get();
}
void join() {
m_internalThread.join();
}
void detach() {
m_internalThread.detach();
}
bool joinable() const {
return m_internalThread.joinable();
}
void interrupt() {
if (m_flag) {
m_flag->set();
}
}
private:
std::thread m_internalThread;
InterruptFlag* m_flag;
};
std::mutex mtx;
std::unique_lock<std::mutex> lk(mtx);
int main(int argc, char* argv[]) {
std::cout << "Interrupting thread example" << std::endl;
bool test = false;
std::condition_variable cv;
auto f = [&cv, &test]() {
test = true;
InterruptibleWait(cv, lk);
// Since it locks forever, it should never reach this point.
test = false;
};
Interruptible interruptibleThread(f);
std::this_thread::sleep_for(std::chrono::milliseconds(30));
// We interrupt the function while it's blocked in InterruptibleWait
interruptibleThread.interrupt();
interruptibleThread.join();
std::cout << "test value is " << std::boolalpha << test << ". It should be true." << std::endl;
return 0;
}
Basically I create a Interruptible class representing a thread that can be interrupted. I interrupt it during its execution by calling its interrupt() method. The thread can be interrupted if it's locked with in a InterruptibleWait function call. This function behave like a std::condition.wait(), in fact it wants a reference to it, but it also handle the interruption flag.
If I start the program. I obtain an error from Visual Studio when running.
I don't know what I'm doing wrong. What should I do in order to make InterruptibleWait work correctly?
My best guess based on the given information:
The exception isn't caught in the thread entry point function, and escapes that function. When this happens in a thread started by std::thread, abort is called for you (indirectly through std::terminate) by the std::thread implementation, as required by the standard. To fix this, try catching all exceptions in the function passed to std::thread.
See the cppreference articles on std::thread and std::terminate
#ifndef THREADPOOL_H
#define THREADPOOL_H
#include <iostream>
#include <deque>
#include <functional>
#include <thread>
#include <condition_variable>
#include <mutex>
#include <atomic>
#include <vector>
//thread pool
class ThreadPool
{
public:
ThreadPool(unsigned int n = std::thread::hardware_concurrency())
: busy()
, processed()
, stop()
{
for (unsigned int i=0; i<n; ++i)
workers.emplace_back(std::bind(&ThreadPool::thread_proc, this));
}
template<class F> void enqueue(F&& f)
{
std::unique_lock<std::mutex> lock(queue_mutex);
tasks.emplace_back(std::forward<F>(f));
cv_task.notify_one();
}
void waitFinished()
{
std::unique_lock<std::mutex> lock(queue_mutex);
cv_finished.wait(lock, [this](){ return tasks.empty() && (busy == 0); });
}
~ThreadPool()
{
// set stop-condition
std::unique_lock<std::mutex> latch(queue_mutex);
stop = true;
cv_task.notify_all();
latch.unlock();
// all threads terminate, then we're done.
for (auto& t : workers)
t.join();
}
unsigned int getProcessed() const { return processed; }
private:
std::vector< std::thread > workers;
std::deque< std::function<void()> > tasks;
std::mutex queue_mutex;
std::condition_variable cv_task;
std::condition_variable cv_finished;
unsigned int busy;
std::atomic_uint processed;
bool stop;
void thread_proc()
{
while (true)
{
std::unique_lock<std::mutex> latch(queue_mutex);
cv_task.wait(latch, [this](){ return stop || !tasks.empty(); });
if (!tasks.empty())
{
// got work. set busy.
++busy;
// pull from queue
auto fn = tasks.front();
tasks.pop_front();
// release lock. run async
latch.unlock();
// run function outside context
fn();
++processed;
latch.lock();
--busy;
cv_finished.notify_one();
}
else if (stop)
{
break;
}
}
}
};
#endif // THREADPOOL_H
I have the above thread pool implementation using a latch. However, every time I add a task through the enqueue call, the overhead is quite large, it takes about 100 micro seconds.
How can I improve the performance of the threadpool?
Your code looks fine. The comments above in your question about compiling with release optimizations on are probably correct and all you need to do.
Disclaimer: Always measure code first with appropriate tools to identify where the bottlenecks are before attempting to improve it's performance. Otherwise, you might not get the improvements you seek.
But a couple of potential micro-optimizations I see are this.
Change this in your thread_proc function
while (true)
{
std::unique_lock<std::mutex> latch(queue_mutex);
cv_task.wait(latch, [this](){ return stop || !tasks.empty(); });
if (!tasks.empty())
To this:
std::unique_lock<std::mutex> latch(queue_mutex);
while (!stop)
{
cv_task.wait(latch, [this](){ return stop || !tasks.empty(); });
while (!tasks.empty() && !stop)
And then remove the else if (stop) block and the end of the function.
The main impact this has is that it avoids the extra "unlock" and "lock" on queue_mutex as a result of latch going out of scope on each iteration of the while loop. The changing of if (!tasks.empty()) to while (!tasks.empty()) might save a cycle or two as well by letting the currently executing thread which has the quantum keep the lock and try to deque the next work item.
<opinion>
One final thing. I'm always of the opinion that the notify should be outside the lock. That way, there's no lock contention when the other thread is woken up by the thread that just updated the queue. But I've never actually measured this assumption, so take it with a grain of salt:
template<class F> void enqueue(F&& f)
{
queue_mutex.lock();
tasks.emplace_back(std::forward<F>(f));
queue_mutex.unlock();
cv_task.notify_one();
}
Application without std::condition_variable:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <chrono>
std::mutex mutex;
std::queue<int> queue;
int counter;
void loadData()
{
while(true)
{
std::unique_lock<std::mutex> lock(mutex);
queue.push(++counter);
lock.unlock();
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
void writeData()
{
while(true)
{
std::lock_guard<std::mutex> lock(mutex);
while(queue.size() > 0)
{
std::cout << queue.front() << std::endl;
queue.pop();
}
}
}
int main()
{
std::thread thread1(loadData);
std::thread thread2(writeData);
thread1.join();
thread2.join();
return 0;
}
Application with std::condition_variable:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <chrono>
std::mutex mutex;
std::queue<int> queue;
std::condition_variable condition_variable;
int counter;
void loadData()
{
while(true)
{
std::unique_lock<std::mutex> lock(mutex);
queue.push(++counter);
lock.unlock();
condition_variable.notify_one();
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
void writeData()
{
while(true)
{
std::unique_lock<std::mutex> lock(mutex);
condition_variable.wait(lock, [](){return !queue.empty();});
std::cout << queue.front() << std::endl;
queue.pop();
}
}
int main()
{
std::thread thread1(loadData);
std::thread thread2(writeData);
thread1.join();
thread2.join();
return 0;
}
If I am right, it means that second version of this application is unsafe, because of queue.empty() function, which is used without any synchronization, so there are no locks. And there is my question: Should we use condition_variables if they cause problems like this one mentioned before?
Your first example busy waits -- there is a thread pounding on the lock, checking, then releasing the lock. This both increases contention of the mutex and wastes up to an entire CPU when nothing is being processed.
The second example has the waiting thread mostly sleeping. It only wakes up when there is data ready, or when there is a "spurious wakeup" (with the standard permits).
When it wakes up, it reacquires the mutex and checks the predicate. If the predicate fails, it releases the lock and waits on the condition variable again.
It is safe, because the predicate is guaranteed to be run within the mutex you acquired and passed to the wait function.
The second code is safe because the call to wait(lock, pred) is equivalent to (directly from the standard):
while (!pred())
wait(lock);
And a call to wait(lock) release (unlock) lock, and reacquire (lock) it on notification.
In your case, this is equivalent to:
auto pred = [](){return !queue.empty();};
std::unique_lock<std::mutex> lock(mutex); // acquire
while (!pred) { // Ok, we are locked
condition_variable.wait(lock); // release
// if you get here, the lock as been re-acquired
}
So all the calls to your pred are made with lock locked/acquired - No issue here as long as all other operations to queue are also guarded.
I encountered some problem and I'm not sure how to deal with it.
#include <iostream>
#include <thread>
#include <condition_variable>
#include <chrono>
std::condition_variable CV;
std::mutex m;
std::size_t i{0};
void set_value() try
{
std::this_thread::sleep_for(std::chrono::seconds{2});
{
std::lock_guard<std::mutex> lock{m};
i = 20;
}
CV.notify_one();
}
catch(...){
//what to do?
}
int main()
{
std::thread t{set_value};
t.detach();
std::unique_lock<std::mutex> lock{m};
CV.wait(lock, []{ return i != 0; });
std::cout << "i has changed to " << i << std::endl;
}
This of course works fine but how should I handle the case when std::lock_guard::lock throws an exception?
At first I was thinking to create global std::atomic<bool> mutex_lock_throwed{ false }; that I could set to true inside the catch block. Than I could notify_one()
catch(...){
mutex_lock_throwed.store(true);
CV.notify_one();
}
and change predicate for wait function to
[]{ return i != 0 || mutex_lock_throwed.load(); }
This actually worked very well but I read this in cppreference
Even if the shared variable is atomic, it must be modified under the mutex in order to correctly publish the modification to the waiting thread.
As you can see its not possible if mutex throws. So what should be the correct way to handle this?
I am reading about Semaphores. From what I understand is that a Semaphore allows only a certain number of threads to access a specific resource. I came across this post which explains how to create a simple semaphore class using condition variables and a mutex. The code for ease of access is pasted here from that link
#include <mutex>
#include <condition_variable>
class Semaphore {
public:
Semaphore (int count_ = 0)
: count(count) {}
inline void notify()
{
std::unique_lock<std::mutex> lock(mtx);
count++;
cv.notify_one();
}
inline void wait()
{
std::unique_lock<std::mutex> lock(mtx);
while(count == 0){
cv.wait(lock);
}
count--;
}
private:
std::mutex mtx;
std::condition_variable cv;
int count;
};
My question is how would I use the above class to make this method accessible to only 3 threads at a time
void SomeFunction
{
------------------------------> Only 3 threads should be allowed access to this function concurrently
int a = getSomeValue();
//Do something useful
------------------------------>
}
I am thinking that I would do something like this
Semaphore s(3);
void SomeFunction
{
s.wait();
int a = getSomeValue();
//Do sometning useful
s.notify();
}
However I am not sure when wait() and notify() would be called ?
It would be better to use RAII idiom for a semaphore:
class SemaphoreLock
{
public:
SemaphoreLock(Semaphore& s)
: _pS(&s)
{
_pS->wait();
}
~SemaphoreLock()
{
_pS->notify();
}
private:
Semaphore* _pS;
};
Semaphore s(3);
void SomeFunction()
{
SemaphoreLock sl(s);
// implement the function here
}
If SemaphoreLock object is declared in the very beginning of the body of the function, then wait() would be called upon entering the function and notify() would be called just before exiting the function, also in the case if an exception is thrown and stack unwinding is not terminated.
An even better solution could be in renaming the methods of Semaphore: wait into lock and notify into unlock. In this case one would be able to use std::lock_guard<Semaphore> in place of self-written SemaphoreLock class.