I have two threads, one thread should receive and process requests from another. The second is to transfer requests and receive a response synchronously. I tried the following scheme: queue of pair (value, promise). The first thread creates a promise and pushed it in synchronous queue and waiting for a return value by future.get()
The problem is that sometimes the thread stuck on future.get(), but when i pause program execution and continue it again works correctly. this stucks has random nature.
FutureQueue.h
#ifndef FutureQueue_h
#define FutureQueue_h
#include <queue>
#include <future>
#include <thread>
#include <mutex>
#include <condition_variable>
template <typename T, typename R>
class Work{
public:
Work(){
}
Work(T value, std::promise<R>* promise){
m_value = value;
m_p_promise = promise;
}
std::promise<R>* m_p_promise;
T m_value;
public:
T getValue(){
return m_value;
}
void setResult(R result){
m_p_promise->set_value(result);
}
};
template <typename T, typename R>
class FutureQueue
{
public:
Work<T,R> getWork(){
auto p = pop();
return Work<T,R>(p.first,p.second);
}
R execute(T value)
{
std::promise<R> promise = std::promise<R>();
std::future<R> f = promise.get_future();
auto p = std::pair<T, std::promise<R>*>(value, &promise);
push(p);
return f.get();
}
private:
std::pair<T,std::promise<R>*> pop(){
std::unique_lock<std::mutex> mlock(mutex_);
while (queue_.empty())
{
cond_.wait(mlock);
}
auto item = queue_.front();
queue_.pop();
return item;
}
void push(const std::pair<T,std::promise<R>*>& item){
std::unique_lock<std::mutex> mlock(mutex_);
queue_.push(item);
mlock.unlock();
cond_.notify_one();
}
std::queue<std::pair<T,std::promise<R>*>> queue_;
std::mutex mutex_;
std::condition_variable cond_;
};
#endif
main.cpp
#include <iostream>
#include <thread>
#include "FutureQueue.h"
using namespace std;
atomic<bool> quit;
FutureQueue<int, int> mQueue;
void consumer(){
Work<int,int> work;
while(true){
work = mQueue.getWork();
if (quit){
break;
}
int value = work.getValue()+100;
work.setResult(value);
}
work.setResult(0);
}
int main(int argc, const char * argv[]) {
quit = false;
thread thread(consumer);
// test 2
for (int i=0;i<100000;i++){
int value = mQueue.execute(i);
cout << "input " << i <<" execute result " << value << endl;
}
quit = true;
mQueue.execute(-1);
thread.join();
return 0;
}
I don't know whats wrong with this code, maybe you can suggest better solution. Thank you
UPDATE
Stucks occurs only in os x with Apple LLVM version 6.0
There is no problem under gcc on OS X and Linux and Visual studio on Windows
There are two threads, A with
for (int i=0;i<100000;i++){
int value = mQueue.execute(i);
cout << "input " << i <<" execute result " << value << endl;
}
quit = true;
mQueue.execute(-1);
B with
thread thread(consumer);
You expect B first Run, then stuck because
while (queue_.empty())
{
cond_.wait(mlock);
}
B will continue run until A run the following code
cond_.notify_one();
Usually it will be ok. But if A first fun "cond.notify_one()", the B call "con_.wait(mlock)", the B will be stuck forever.
Related
Here is some code which increments several chronometers in parallel:
main.cpp
using namespace std;
#include <stdio.h>
#include <time.h>
#include <iostream>
#include <math.h>
#include <cstdlib>
#include <unistd.h>
#include <iostream>
#include <sstream>
#include <thread>
#include <vector>
#include <future>
#include "mychrono.hpp"
int main()
{
std::vector<Chronometer*> car_crono;
Chronometer chrono, output_chrono;
std::vector<std::thread> threads;
std::vector<std::future<Chronometer&>> futures;
std::thread th;
//future<Chronometer> ft;
for(int i = 0; i < 2; i++)
{
car_crono.push_back(new Chronometer);
}
while (1) {
for(int i = 0; i<2; i++)
{
//
// //threads.push_back(std::thread(&Chronometer::start_chrono, car_crono[i], std::ref(chrono)));
// auto ft = std::async(std::launch::async, &Chronometer::start_chrono, car_crono[i], std::ref(chrono));
//
// std::cout << "Hello-world" << std::endl;
futures.emplace_back(std::async(std::launch::async, &Chronometer::start_chrono, car_crono[i], std::ref(chrono)));
}
std::cout << "hello-world" << std::endl;
//auto ft = std::async(std::launch::async, &Chronometer::start_chrono, car_crono[0], std::ref(chrono));
//std::cout << "Hello-world-2" << std::endl;
for(auto&& f: futures){
std::cout << f.get() << '\n';
}
}
car_crono.clear();
}
mychrono.cpp
#include "mychrono.hpp"
#include <time.h>
#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <sstream>
#include <thread>
//int Chronometer::hour(0), min(0), sec(0);
Chronometer::Chronometer() : hour(0), min(0), sec(0)
{
}
Chronometer& Chronometer::start_chrono(Chronometer& chrono)
{
// if(chrono.hour == 0 && chrono.min == 0 && chrono.sec == 0)
// {
bool condition = true;
while(condition) {
sleep(1);
chrono.sec++;
if(chrono.sec > 59) {
chrono.min++;
chrono.sec = 0;
}
if(chrono.min > 59) {
chrono.hour++;
chrono.sec = 0;
chrono.min = 0;
}
// if(chrono.sec == 10)
// {
// condition = false;
// }
std::cout << "chrono: " << chrono << std::endl;
}
return chrono;
//}
}
Chronometer& Chronometer::finish_chrono(Chronometer& chrono)
{
chrono.hour = 0;
chrono.sec = 0;
chrono.min = 0;
return chrono;
}
std::ostream& operator<<(std::ostream& flux, Chronometer t)
{
flux << t.hour << ":" << t.min << ":" << t.sec;
return flux;
}
Chronometer& Chronometer::operator=(const Chronometer& other)
{
// Guard self assignment
//if (this == &other)
return *this;
}
Chronometer::~Chronometer(){}
mychrono.hpp
#include <time.h>
#include <iostream>
#include <sstream>
#ifndef mychrono_hpp
#define mychrono_hpp
class Chronometer
{
private:
int hour, min, sec;
//std::stringstream ss;
//Chronometer chrono;
public:
Chronometer();
Chronometer& start_chrono(Chronometer& chrono);
Chronometer& finish_chrono(Chronometer& chrono);
friend std::ostream& operator<<(std::ostream& flux, Chronometer t);
Chronometer& operator=(const Chronometer& other);
~Chronometer();
};
#endif
My program runs well my two chronometers in parallel each other but still dependant of my while loop. For example here I will print "hello-world" once but need to wait my threads stop to print a second "hello-world" message in my while loop.
My question is how to make my threads runs in parallel an be completely independant of others instructions in my while loop ?
Tzig had a similar idea as mine, that is using condition variables and such.
I've made a full working example including comments and hopefully written for readability.
#include <chrono>
#include <iostream>
#include <iomanip>
#include <mutex>
#include <future>
#include <condition_variable>
//-----------------------------------------------------------------------------------------------------
// state of the timer.
enum class State
{
idle,
starting,
running,
stopping,
stopped
};
//-----------------------------------------------------------------------------------------------------
// helper class for use of std::condition_variable, makes code more readable
// takes into account the pitfalls of condition variables :
// https://www.modernescpp.com/index.php/c-core-guidelines-be-aware-of-the-traps-of-condition-variables
template<typename T>
class StateVariable
{
public:
StateVariable() = delete;
StateVariable(const StateVariable&) = delete;
StateVariable(StateVariable&&) = delete;
StateVariable& operator=(const StateVariable&) = delete;
explicit StateVariable(const T& value) :
m_value{ value }
{
}
void operator=(const T& value) noexcept
{
{
std::unique_lock<std::mutex> lock(m_value_mutex);
m_value = value;
}
m_value_changed.notify_all();
}
// atomic check and set
T set_if(const T& from_value, const T& to_value) noexcept
{
{
std::unique_lock<std::mutex> lock(m_value_mutex);
if (m_value != from_value) return from_value;
m_value = to_value;
}
m_value_changed.notify_all();
return to_value;
}
const bool try_wait_for(const T& value, const std::chrono::steady_clock::duration& duration) const noexcept
{
auto pred = [this, value] { return (m_value == value); };
std::unique_lock<std::mutex> lock(m_value_mutex);
if (pred()) return true;
return m_value_changed.wait_for(lock, duration, pred);
}
void wait_for(const T& value) const
{
try_wait_for(value, std::chrono::steady_clock::duration::max());
}
private:
// mutables so I could make the const promises on wait
// that they wont change the observable state (m_value)
// of this class.
mutable std::mutex m_value_mutex;
mutable std::condition_variable m_value_changed;
std::atomic<T> m_value;
};
//-----------------------------------------------------------------------------------------------------
// helper class for storing elapsed time, helps with readability later on
class ElapsedTime
{
public:
explicit ElapsedTime(const std::chrono::steady_clock::duration& duration) :
m_duration{ duration }
{
}
auto hours() const
{
return std::chrono::duration_cast<std::chrono::hours>(m_duration).count();
}
auto minutes() const
{
return (std::chrono::duration_cast<std::chrono::minutes>(m_duration).count() % 60);
}
auto seconds() const
{
return (std::chrono::duration_cast<std::chrono::seconds>(m_duration).count() % 60);
}
private:
std::chrono::steady_clock::duration m_duration;
};
//-----------------------------------------------------------------------------------------------------
// formatter for ElapsedTime
std::ostream& operator<<(std::ostream& os, const ElapsedTime& t)
{
os << std::setfill('0') << std::setw(2) << t.hours() << ':';
os << std::setfill('0') << std::setw(2) << t.minutes() << ':';
os << std::setfill('0') << std::setw(2) << t.seconds();
return os;
}
//-----------------------------------------------------------------------------------------------------
// ChronoMeter class
// note I use std::chrono classes
class ChronoMeter final
{
public:
ChronoMeter() :
m_state{ State::idle },
m_duration{ std::chrono::steady_clock::duration::min() }
{
};
ChronoMeter(const ChronoMeter&) = delete;
ChronoMeter(ChronoMeter&&) = delete;
ChronoMeter& operator=(const ChronoMeter&) = delete;
void Start()
{
m_start_time = std::chrono::steady_clock::now();
// exercise for the reader, also allow stopped Chronometers to be restarted.
// for now just this simple state model
if (m_state.set_if(State::idle, State::starting) != State::starting)
{
throw std::runtime_error("only an idle ChronoMeter can be started");
}
// it is okay to capture "this" because the destructor of the
// chronometer synchronizes with termination of this thread through the future
m_future = std::async(std::launch::async, [this]
{
// Set indication that the thread has really started.
// this is important because when std::async returns, this thread exists
// but may not have been scheduled yet.
m_state = State::running;
do
{
// assigning a value to m_duration isn't atomic so protect it.
// we might be reading the value on another thread which might
// result in reading an intermediate state.
std::scoped_lock<std::mutex> lock{ m_data_mtx };
m_duration = std::chrono::steady_clock::now() - m_start_time;
// using a statevariable to check for stopping means it can respond
// during the one second delay and stop immediately.
// this is an advantage over using sleep
} while (!m_state.try_wait_for(State::stopping, std::chrono::seconds(1)));
m_state = State::stopped;
});
// Wait for the thread to have really started
// this way we have a clear post condition for start
m_state.wait_for(State::running);
}
void Stop()
{
// only allow a running Chronometer to be stopped.
// in all other states Stop does nothing
if (m_state.set_if(State::running, State::stopping) == State::stopping)
{
// synchronization with stopped state, as set by other thread
m_state.wait_for(State::stopped);
// future get is not really needed for synchronization.
// but if thread threw an exception it's rethrown here
m_future.get();
}
}
~ChronoMeter()
{
// Automatically stop thread if this hasn't already happened.
Stop();
}
const ElapsedTime Elapsed() const
{
std::scoped_lock<std::mutex> lock{ m_data_mtx };
return ElapsedTime{ m_duration };
}
private:
std::future<void> m_future;
StateVariable<State> m_state;
mutable std::mutex m_data_mtx;
std::chrono::steady_clock::time_point m_start_time;
std::chrono::steady_clock::duration m_duration;
};
int main()
{
ChronoMeter meter1;
ChronoMeter meter2;
meter1.Start();
std::this_thread::sleep_for(std::chrono::seconds(5));
auto elapsed_1_1 = meter1.Elapsed();
std::cout << "Meter 1 elapsed time " << elapsed_1_1 << std::endl;
meter2.Start();
std::this_thread::sleep_for(std::chrono::seconds(4));
auto elapsed_1_2 = meter1.Elapsed();
auto elapsed_2 = meter2.Elapsed();
std::cout << "Meter 1 elapsed time " << elapsed_1_2 << std::endl;
std::cout << "Meter 2 elapsed time " << elapsed_2 << std::endl;
meter1.Stop();
// not stopping meter2 (and it's thread) explicitly, this is done safely by destructor if needed
return 0;
}
I usually solve this problem by making the multithreaded object handle everything that has to do with multithreading, here's how I solved it in your case (I ended up rewriting a lot of things so maybe the behavior isn't exactly the one you want, you can use my code as a starting point):
main.cpp:
#include <iostream>
#include <vector>
#include "mychrono.hpp"
int main()
{
std::vector<Chronometer*> car_crono;
for(int i = 0; i < 2; i++)
{
car_crono.push_back(new Chronometer);
}
while (1) {
// std::cout << "hello-world" << std::endl;
Chronometer::Time t = car_crono[0]->get_time();
if(t.sec >= 10)
car_crono[0]->reset_chrono();
std::cout << "Seconds of T0: " << t.sec << std::endl;
std::cout << "T1: " << car_crono[1]->to_string() << std::endl;
}
car_crono.clear();
}
mychrono.hpp:
#ifndef mychrono_hpp
#define mychrono_hpp
#include <iostream>
#include <thread>
#include <memory>
#include <condition_variable>
#include <mutex>
#include <atomic>
class Chronometer
{
public:
struct Time {
int hour;
int min;
int sec;
};
Chronometer();
void reset_chrono();
friend std::ostream& operator<<(std::ostream& flux, Chronometer& t);
Chronometer& operator=(const Chronometer& other);
std::string to_string();
Time get_time();
~Chronometer();
private:
Time currentTime;
std::mutex timeMutex;
std::condition_variable conditionVariable;
std::unique_ptr<std::thread> thread;
std::mutex CVMutex;
std::atomic<bool> exitNow;
void thread_function();
};
#endif
mychrono.cpp:
#include "mychrono.hpp"
Chronometer::Chronometer() : currentTime.hour(0), currentTime.min(0), currentTime.sec(0)
{
thread.reset(new std::thread(&Chronometer::thread_function, this));
}
void Chronometer::reset_chrono()
{
std::lock_guard<std::mutex> lock(timeMutex);
currentTime.hour = 0;
currentTime.sec = 0;
currentTime.min = 0;
}
std::ostream& operator<<(std::ostream& flux, Chronometer& t)
{
flux << t.to_string();
return flux;
}
Chronometer& Chronometer::operator=(const Chronometer& other)
{
// Guard self assignment
//if (this == &other)
return *this;
}
std::string Chronometer::to_string()
{
std::lock_guard<std::mutex> lock(timeMutex);
return std::to_string(currentTime.hour) + ":" + std::to_string(currentTime.min) + ":" + std::to_string(currentTime.sec);
}
Time Chronometer::get_time()
{
return currentTime;
}
Chronometer::~Chronometer()
{
exitNow = true;
{
std::unique_lock<std::mutex> lock(CVMutex);
lock.unlock();
conditionVariable.notify_all();
}
thread->join();
}
void Chronometer::thread_function()
{
std::unique_lock<std::mutex> waitLock(CVMutex);
while(!exitNow)
{
sec++;
if(currentTime.sec > 59) {
std::lock_guard<std::mutex> lock(timeMutex);
currentTime.min++;
currentTime.sec = 0;
}
if(currentTime.min > 59) {
std::lock_guard<std::mutex> lock(timeMutex);
currentTime.hour++;
currentTime.sec = 0;
currentTime.min = 0;
}
// std::cout << "chrono: " << *this << std::endl; //Not thread safe be careful
conditionVariable.wait_for(waitLock, std::chrono::seconds(1));
}
}
EDIT: About your latest comment: you don't need to reset a chrono in its destructor as the data will be destroyed anyway. If you want to reset the counter while it's running you want to call Chronometer::reset_chrono() from you main function.
For the second part of your comment, I added a get_time function to the code (I also added a mutex to avoid data races, I completly forgot when I wrote the original answer). When you want to get the current time of a chrono from the main function you just call get_time() and use the struct it returns to get the info you want.
I added a small example to show how to use both functions. As you can see, the main function doesn't even need to know what threads are !
I may be wrong but from the questions you ask I feel maybe you're not used to how multithreading works. It's a very difficult concept and one of the few I feel you can't learn only through experience, if that's the case you might want to learn about it from dedicated sites such as this one. I think I pieced together that you speak french, here's a really good article (that was never finished apparently) about the theory of it and another one in french, more about the specifics of C++. If you understand the core concepts and just have a hard time with my code, I plan on commenting it all but for now Pepijn Kramer did a great job explaining what they did in their response.
I am trying to create a data structure, ExpiringDeque. It should be somewhat similar to std::deque. Let's say I need only push_back(), size() and pop_front(). The data structure needs to automatically expire up to N first elements every T seconds.
This data structure needs to manage its own queue and expiration thread internally.
How do I write it in a thread safe way? This is an example that I came up with, does this seem reasonable? What am I missing?
#include <algorithm>
#include <atomic>
#include <cassert>
#include <deque>
#include <mutex>
#include <thread>
#include <unistd.h>
#include <iostream>
template <typename T>
class ExpiringDeque {
public:
ExpiringDeque(int n, int t) : numElements_(n), interval_(t), running_(true), items_({}) {
expiringThread_ = std::thread{[&] () {
using namespace std::chrono_literals;
int waitCounter = 0;
while (true) {
if (!running_) {
return;
}
std::this_thread::sleep_for(1s);
if (waitCounter++ < interval_) {
continue;
}
std::lock_guard<std::mutex> guard(mutex_);
waitCounter = 0;
int numToErase = std::min(numElements_, static_cast<int>(items_.size()));
std::cout << "Erasing " << numToErase << " elements\n";
items_.erase(items_.begin(), items_.begin() + numToErase);
}
}};
}
~ExpiringDeque() {
running_ = false;
expiringThread_.join();
}
T pop_front() {
if (items_.size() == 0) {
throw std::out_of_range("Empty deque");
}
std::lock_guard<std::mutex> guard(mutex_);
T item = items_.front();
items_.pop_front();
return item;
}
int size() {
std::lock_guard<std::mutex> guard(mutex_);
return items_.size();
}
void push_back(T item) {
std::lock_guard<std::mutex> guard(mutex_);
items_.push_back(item);
}
private:
int numElements_;
int interval_;
std::atomic<bool> running_;
std::thread expiringThread_;
std::mutex mutex_;
std::deque<T> items_;
};
int main() {
ExpiringDeque<int> ed(10, 3);
ed.push_back(1);
ed.push_back(2);
ed.push_back(3);
assert(ed.size() == 3);
assert(ed.pop_front() == 1);
assert(ed.size() == 2);
// wait for expiration
sleep(5);
assert(ed.size() == 0);
ed.push_back(10);
assert(ed.size() == 1);
assert(ed.pop_front() == 10);
return 0;
}
You can avoid an unnecessary wait in the destructor of ExpiringDeque by using a condition variable. I would also use std::condition_variable::wait_for with a predicate to check the running_ flag. This will ensure that you either wait for a timeout or a notification, whichever is earlier. You avoid using waitCounter and continue this way.
Another thing you should do is lock the mutex before checking the size of your deque in pop_front(), otherwise it's not thread safe.
Here's an updated version of your code:
template <typename T>
class ExpiringDeque {
public:
ExpiringDeque(int n, int t) : numElements_(n), interval_(t), running_(true), items_({}), cv_() {
expiringThread_ = std::thread{ [&]() {
using namespace std::chrono_literals;
while (true) {
//Wait for timeout or notification
std::unique_lock<std::mutex> lk(mutex_);
cv_.wait_for(lk, interval_ * 1s, [&] { return !running_; });
if (!running_)
return;
//Mutex is locked already - no need to lock again
int numToErase = std::min(numElements_, static_cast<int>(items_.size()));
std::cout << "Erasing " << numToErase << " elements\n";
items_.erase(items_.begin(), items_.begin() + numToErase);
}
} };
}
~ExpiringDeque() {
//Set flag and notify worker thread
{
std::lock_guard<std::mutex> lk(mutex_);
running_ = false;
}
cv_.notify_one();
expiringThread_.join();
}
T pop_front() {
std::lock_guard<std::mutex> guard(mutex_);
if (items_.size() == 0) {
throw std::out_of_range("Empty deque");
}
T item = items_.front();
items_.pop_front();
return item;
}
...
private:
int numElements_;
int interval_;
bool running_;
std::thread expiringThread_;
std::mutex mutex_;
std::deque<T> items_;
std::condition_variable cv_;
};
You can make the running_ flag a normal bool since the std::condition_variable::wait_for atomically checks for the timeout or notification.
I am trying to make a thread safe queue in C++17 based on condition variables.
How do I correctly interrupt the WaitAndPop() method in the queue's destructor?
The problem is that user classes will be waiting on the WaitAndPop() call to return before they destruct, meaning that their member queue never destructs, meaning that the return never happens, and I have a deadlock.
Here is a simplified example that illustrates the problem:
#include <condition_variable>
#include <future>
#include <iostream>
#include <mutex>
#include <queue>
#include <thread>
using namespace std;
using namespace chrono_literals;
class ThreadsafeQueue {
private:
condition_variable cv_;
bool cancel_;
mutex mut_;
queue<int> queue_;
public:
ThreadsafeQueue() : cancel_(false){};
~ThreadsafeQueue() {
// although this would stop the cv, it never runs.
cancel_ = true;
cv_.notify_all();
scoped_lock<mutex> lk(mut_);
}
void Push(int x) {
{
scoped_lock<mutex> lk(mut_);
queue_.push(x);
}
cv_.notify_all();
}
// returns true if successful
bool WaitAndPop(int &out) {
unique_lock<mutex> lk(mut_);
cv_.wait(lk, [this]() { return cancel_ || ! queue_.empty(); });
if (cancel_) return false;
out = queue_.front();
queue_.pop();
return true;
}
};
class MyClass {
private:
future<void> fill_fut_;
future<void> serve_fut_;
ThreadsafeQueue queue_;
bool running_;
public:
MyClass() : running_(true) {
fill_fut_ = async(launch::async, &MyClass::FillThread, this);
serve_fut_ = async(launch::async, &MyClass::ServeThread, this);
};
~MyClass() {
running_ = false;
fill_fut_.get();
serve_fut_.get(); // this prevents the threadsafe queue from destructing,
// which
// prevents the serve thread from stopping.
}
void FillThread() {
while (running_) {
queue_.Push(rand() & 100);
this_thread::sleep_for(200ms);
}
}
void ServeThread() {
while (running_) {
int x;
bool ok = queue_.WaitAndPop(x); // this never returns because the queue
// never destructs
if (ok)
cout << "popped: " << x << endl; // prints five times
else
cout << "pop failed"; // does not reach here
}
}
};
int main() {
MyClass obj;
this_thread::sleep_for(1s);
return 0;
}
In my code I want my system to sleep, until a condition has been met. An after having searched i have found #include <unistd.h>, but to me it just looks like it sleeps until the time frame has been met. I was wondering if there was a easy way to make the program wait until the condition has been reached.
Here you have a sample of the code to clarify my point
bool check() {
while (condition) {
sleep.here();
} else {
run.the.rest();
}
}
Based on your incomplete pseudo-code and description, here is a class contidion_t, where you can set your condition via set_condition, and a thread blocking in loop will wake up, every time you set it.
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <atomic>
struct condition_t {
public:
template <typename T>
void loop(T the_rest) {
while(running) {
std::unique_lock<std::mutex> lock_guard(m);
cv.wait(lock_guard, [this] { return ready.load(); });
the_rest();
ready = false;
}
}
void set_condition(bool value) {
ready = value;
if (value) {
cv.notify_one();
}
}
void stop_running() {
running = false;
ready = true;
cv.notify_all();
}
~condition_t () {stop_running();}
private:
std::mutex m;
std::condition_variable cv;
std::atomic<bool> ready{false};
std::atomic<bool> running{true};
};
int main() {
condition_t condition;
std::thread thread(&condition_t::loop<void (void)>, &condition, [] () {
std::cout << "Doing the rest" << std::endl;
});
std::cout << "Thread created but waits\nInput something for continue:";
int something;
std::cin >> something;
std::cout << "Continueing\n";
condition.set_condition(true);
std::cout << "Input something to stop running:";
std::cin >> something;
condition.stop_running();
thread.join();
}
This is a simple program which has a function start() which waits for user to enter something(using infinite loop) and stores it in queue. start() runs in a separate thread. After user enters some value, the size of queue remains zero in main. How can the queue be synchronized?
code: source.cpp
#include <iostream>
#include "kl.h"
using namespace std;
int main()
{
std::thread t1(start);
while (1)
{
if (q.size() > 0)
{
std::cout << "never gets inside this if\n";
std::string first = q.front();
q.pop();
}
}
t1.join();
}
code: kl.h
#include <queue>
#include <iostream>
#include <string>
void start();
static std::queue<std::string> q;
code: kl.cpp
#include "kl.h"
using namespace std;
void start()
{
char i;
string str;
while (1)
{
for (i = 0; i <= 1000; i++)
{
//other stuff and str input
q.push(str);
}
}
}
Your code contains a race - by me it crashed; both threads are potentially modifying a shared queue. (Also, you're looping with char i for values up to 1000 - not a good idea, probably.)
You should protect your shared queue with a std::mutex, and use a std::condition_variable to notify that there is a reason to check the queue.
Specifically, you should consider the following (which is very common for your case of a producer consumer):
Access the queue only when holding the mutex.
Use the condition variable to notify that you've pushed something into it.
Use the condition variable to specify a condition on when there's a point to continue processing.
Here is a rewrite of your code:
#include <iostream>
#include <queue>
#include <thread>
#include <condition_variable>
#include <mutex>
using namespace std;
std::queue<std::string> q;
std::mutex m;
std::condition_variable cv;
void start()
{
string str;
for (std::size_t i = 0; i <= 1000; i++) {
//other stuff and str input
std::cout << "here" << std::endl;
std::unique_lock<std::mutex> lk(m);
q.push(str);
lk.unlock();
cv.notify_one();
}
}
int main()
{
std::thread t1(start);
for (std::size_t i = 0; i <= 1000; i++)
{
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, []{return !q.empty();});
std::string first = q.front();
q.pop();
}
t1.join();
}
My synced queue class example and its usage:
template<typename T>
class SyncQueue
{
std::queue<T> m_Que;
std::mutex m_Lock;
std::condition_variable m_ConVar;
public:
void enque(T item)
{
std::unique_lock<std::mutex> lock(m_Lock);
m_Que.push(item);
lock.unlock();
m_ConVar.notify_all();
}
T deque()
{
std::unique_lock<std::mutex> lock(m_Lock);
do
{
m_ConVar.wait(lock);
} while(m_Que.size() == 0); // extra check from spontaneous notifications
auto ret = m_Que.front();
m_Que.pop();
return ret;
}
};
int main()
{
using namespace std::chrono_literals;
SyncQueue<int> sq;
std::thread consumer([&sq]()
{
std::cout << "consumer" << std::endl;
for(;;)
{
std::cout << sq.deque() << std::endl;
}
});
std::thread provider([&sq]()
{
std::this_thread::sleep_for(1s);
sq.enque(1);
std::this_thread::sleep_for(3s);
sq.enque(2);
std::this_thread::sleep_for(5s);
sq.enque(3);
});
consumer.join();
return 0;
}
/* Here I have a code snippate with Separate class for
Producing and Consuming along with buffer class */
#include <iostream>
#include <mutex>
#include <condition_variable>
#include <thread>
#include <deque>
#include <vector>
using namespace std;
mutex _mutex_1,_mutex_2;
condition_variable cv;
template <typename T>
class Queue
{
deque<T> _buffer;
const unsigned int max_size = 10;
public:
Queue() = default;
void push(const T& item)
{
while(1)
{
unique_lock<mutex> locker(_mutex_1);
cv.wait(locker,[this](){ return _buffer.size() < max_size; });
_buffer.push_back(item);
locker.unlock();
cv.notify_all();
return;
}
}
T pop()
{
while(1)
{
unique_lock<mutex> locker(_mutex_1);
cv.wait(locker,[this](){ return _buffer.size() > 0; });
int back = _buffer.back();
_buffer.pop_back();
locker.unlock();
cv.notify_all();
return back;
}
}
};
class Producer
{
Queue<int>* _buffer;
public:
Producer(Queue<int>* _buf)
{
this->_buffer = _buf;
}
void run()
{
while(1)
{
auto num = rand()%100;
_buffer->push(num);
_mutex_2.lock();
cout<<"Produced:"<<num<<endl;
this_thread::sleep_for(std::chrono::milliseconds(50));
_mutex_2.unlock();
}
}
};
class Consumer
{
Queue<int>* _buffer;
public:
Consumer(Queue<int>* _buf)
{
this->_buffer = _buf;
}
void run()
{
while(1)
{
auto num = _buffer->pop();
_mutex_2.lock();
cout<<"Consumed:"<<num<<endl;
this_thread::sleep_for(chrono::milliseconds(50));
_mutex_2.unlock();
}
}
};
void client()
{
Queue<int> b;
Producer p(&b);
Consumer c(&b);
thread producer_thread(&Producer::run, &p);
thread consumer_thread(&Consumer::run, &c);
producer_thread.join();
consumer_thread.join();
}
int main()
{
client();
return 0;
}