I would like to reorder the handlers processed by a boost io_service:
This is my pseudocode:
start()
{
io.run();
}
thread1()
{
io.post(myhandler1);
}
thread2()
{
io.post(myhandler2);
}
thread1() and thread2() are called independently.
In this case, the io_service processes the handler in the post order.
Queue example: myhandler1|myhandler1|myhandler2|myhandler1|myhandler2
How to modify the io_service processing order to execute myhandler1 and myhandler2 one after the other ?
New Queue example: myhandler1|myhandler2|myhandler1|myhandler2|myhandler1
I wrote this code but CPU usage is 100%:
start()
{
while(1)
{
io1.poll_one();
io2.poll_one();
}
}
thread1()
{
io1.post(myhandler1);
}
thread2()
{
io2.post(myhandler2);
}
Thanks
I'd use two queues. From this ASIO anwer I made once (Non blocking boost io_service for deadline_timers) I took the thread_pool class.
I split it into task_queue and thread_pool classes.
I created a worker type that knows how to juggle two queues:
struct worker {
task_queue q1, q2;
void wake() {
q1.wake();
q2.wake();
}
void operator()(boost::atomic_bool& shutdown) {
std::cout << "Worker start\n";
while (true) {
auto job1 = q1.dequeue(shutdown);
if (job1) (*job1)();
auto job2 = q2.dequeue(shutdown);
if (job2) (*job2)();
if (shutdown && !(job1 || job2))
break;
}
std::cout << "Worker exit\n";
}
};
You can see how the worker loop is structured so that - if tasks are enqueued - queues will be served in alternation.
Note: the wake() call is there for reliable shutdown; the queues use blocking waits, and hence they will need to be signaled (woken up) when the shutdown flag is toggled.
Full Demo
Live On Coliru
#include <boost/function.hpp>
#include <boost/optional.hpp>
#include <boost/thread.hpp>
#include <boost/atomic.hpp>
#include <iostream>
#include <deque>
namespace custom {
using namespace boost;
class task_queue {
private:
mutex mx;
condition_variable cv;
typedef function<void()> job_t;
std::deque<job_t> _queue;
public:
void enqueue(job_t job)
{
lock_guard<mutex> lk(mx);
_queue.push_back(job);
cv.notify_one();
}
template <typename T>
optional<job_t> dequeue(T& shutdown)
{
unique_lock<mutex> lk(mx);
cv.wait(lk, [&] { return shutdown || !_queue.empty(); });
if (_queue.empty())
return none;
job_t job = _queue.front();
_queue.pop_front();
return job;
}
void wake() {
lock_guard<mutex> lk(mx);
cv.notify_all();
}
};
template <typename Worker> class thread_pool
{
private:
thread_group _pool;
boost::atomic_bool _shutdown { false };
Worker _worker;
void start() {
for (unsigned i = 0; i < 1 /*boost::thread::hardware_concurrency()*/; ++i){
std::cout << "Creating thread " << i << "\n";
_pool.create_thread([&] { _worker(_shutdown); });
}
}
public:
thread_pool() { start(); }
~thread_pool() {
std::cout << "Pool going down\n";
_shutdown = true;
_worker.wake();
_pool.join_all();
}
Worker& get_worker() { return _worker; }
};
struct worker {
task_queue q1, q2;
void wake() {
q1.wake();
q2.wake();
}
void operator()(boost::atomic_bool& shutdown) {
std::cout << "Worker start\n";
while (true) {
auto job1 = q1.dequeue(shutdown);
if (job1) (*job1)();
auto job2 = q2.dequeue(shutdown);
if (job2) (*job2)();
if (shutdown && !(job1 || job2))
break;
}
std::cout << "Worker exit\n";
}
};
}
void croak(char const* queue, int i) {
static boost::mutex cout_mx;
boost::lock_guard<boost::mutex> lk(cout_mx);
std::cout << "thread " << boost::this_thread::get_id() << " " << queue << " task " << i << "\n";
}
int main() {
custom::thread_pool<custom::worker> pool;
auto& queues = pool.get_worker();
for (int i = 1; i <= 10; ++i) queues.q1.enqueue([i] { croak("q1", i); });
for (int i = 1; i <= 10; ++i) queues.q2.enqueue([i] { croak("q2", i); });
}
Prints e.g.
Creating thread 0
Pool going down
Worker start
thread 7f7311397700 q1 task 1
thread 7f7311397700 q2 task 1
thread 7f7311397700 q1 task 2
thread 7f7311397700 q2 task 2
thread 7f7311397700 q1 task 3
thread 7f7311397700 q2 task 3
thread 7f7311397700 q1 task 4
thread 7f7311397700 q2 task 4
thread 7f7311397700 q1 task 5
thread 7f7311397700 q2 task 5
thread 7f7311397700 q1 task 6
thread 7f7311397700 q2 task 6
thread 7f7311397700 q1 task 7
thread 7f7311397700 q2 task 7
thread 7f7311397700 q1 task 8
thread 7f7311397700 q2 task 8
thread 7f7311397700 q1 task 9
thread 7f7311397700 q2 task 9
thread 7f7311397700 q1 task 10
thread 7f7311397700 q2 task 10
Worker exit
Generalizing it
Here it is generalized for more queues (e.g. three):
Live On Coliru
Note that the above have 1 worker thread servicing; if you created more than 1 thread, each thread individually would alternate between queues, but overall the order would be undefined (because the thread scheduling is undefined).
The generalized version is somewhat more accurate here since it shared the idx variable between worker threads, but the actual output order still depends on thread scheduling.
Using run_one() instead of poll_one() should work (note that reset() is also required):
start()
{
while(1)
{
io1.run_one();
io2.run_one();
io1.reset();
io2.reset();
}
}
However, I don't know if this is a good solution to any actual problem you might have. This is one of those cases where the question, "What are you really trying to do?" seems relevant. For example, if it makes sense to run handler2 after every invocation of handler1, then perhaps handler1 should invoke handler2.
Related
I am looking at multithreading and written a basic producer/consumer. I have two issues with the producer/consumer written below. 1) Even by setting the consumer sleep time lower than the producer sleep time, the producer still seems to execute quicker. 2) In the consumer I have duplicated the code in the case where the producer finishes adding to the queue, but there is still elements in the queue. Any advise for a better way of structuring the code?
#include <iostream>
#include <queue>
#include <mutex>
class App {
private:
std::queue<int> m_data;
bool m_bFinished;
std::mutex m_Mutex;
int m_ConsumerSleep;
int m_ProducerSleep;
int m_QueueSize;
public:
App(int &MaxQueue) :m_bFinished(false), m_ConsumerSleep(1), m_ProducerSleep(5), m_QueueSize(MaxQueue){}
void Producer() {
for (int i = 0; i < m_QueueSize; ++i) {
std::lock_guard<std::mutex> guard(m_Mutex);
m_data.push(i);
std::cout << "Producer Thread, queue size: " << m_data.size() << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(m_ProducerSleep));
}
m_bFinished = true;
}
void Consumer() {
while (!m_bFinished) {
if (m_data.size() > 0) {
std::lock_guard<std::mutex> guard(m_Mutex);
std::cout << "Consumer Thread, queue element: " << m_data.front() << " size: " << m_data.size() << std::endl;
m_data.pop();
}
else {
std::cout << "No elements, skipping" << std::endl;
}
std::this_thread::sleep_for(std::chrono::seconds(m_ConsumerSleep));
}
while (m_data.size() > 0) {
std::lock_guard<std::mutex> guard(m_Mutex);
std::cout << "Emptying remaining elements " << m_data.front() << std::endl;
m_data.pop();
std::this_thread::sleep_for(std::chrono::seconds(m_ConsumerSleep));
}
}
};
int main()
{
int QueueElements = 10;
App app(QueueElements);
std::thread consumer_thread(&App::Consumer, &app);
std::thread producer_thread(&App::Producer, &app);
producer_thread.join();
consumer_thread.join();
std::cout << "loop exited" << std::endl;
return 0;
}
You should use condition_variable. Don't use sleep for threads.
Main scheme:
Producer pushes value under lock and signals condition_variable.
Consumer waits under lock on condition variable and checks predicate to prevent spurious wakeups.
My version:
#include <iostream>
#include <queue>
#include <mutex>
#include <thread>
#include <condition_variable>
#include <atomic>
class App {
private:
std::queue<int> m_data;
std::atomic_bool m_bFinished;
std::mutex m_Mutex;
std::condition_variable m_cv;
int m_QueueSize;
public:
App(int MaxQueue)
: m_bFinished(false)
, m_QueueSize(MaxQueue)
{}
void Producer()
{
for (int i = 0; i < m_QueueSize; ++i)
{
{
std::unique_lock<std::mutex> lock(m_Mutex);
m_data.push(i);
}
m_cv.notify_one();
std::cout << "Producer Thread, queue size: " << m_data.size() << std::endl;
}
m_bFinished = true;
}
void Consumer()
{
do
{
std::unique_lock<std::mutex> lock(m_Mutex);
while (m_data.empty())
{
m_cv.wait(lock, [&](){ return !m_data.empty(); }); // predicate an while loop - protection from spurious wakeups
}
while(!m_data.empty()) // consume all elements from queue
{
std::cout << "Consumer Thread, queue element: " << m_data.front() << " size: " << m_data.size() << std::endl;
m_data.pop();
}
} while(!m_bFinished);
}
};
int main()
{
int QueueElements = 10;
App app(QueueElements);
std::thread consumer_thread(&App::Consumer, &app);
std::thread producer_thread(&App::Producer, &app);
producer_thread.join();
consumer_thread.join();
std::cout << "loop exited" << std::endl;
return 0;
}
Also note, that it's better to use atomic for end flag, when you have deal with concurrent threads, because theoretically value of the m_bFinished will be stored in the cache-line and if there is no cache invalidation in the producer thread, the changed value can be unseen from the consumer thread. Atomics have memory fences, that guarantees, that value will be updated for other threads.
Also you can take a look on memory_order page.
First, you should use a condition variable instead of a delay on the consumer. This way, the consumer thread only wakes up when the queue is not empty and the producer notifies it.
That said, the reason why your producer calls are more frequent is the delay on the producer thread. It's executed while holding the mutex, so the consumer will never execute until the delay is over. You should release the mutex before calling sleep_for:
for (int i = 0; i < m_QueueSize; ++i) {
/* Introduce a scope to release the mutex before sleeping*/
{
std::lock_guard<std::mutex> guard(m_Mutex);
m_data.push(i);
std::cout << "Producer Thread, queue size: " << m_data.size() << std::endl;
} // Mutex is released here
std::this_thread::sleep_for(std::chrono::seconds(m_ProducerSleep));
}
I have a requirement to post a task from child thread to main thread back. I am creating child thread from the main thread and posting tasks over there. But after receiving few callbacks from common API, I need to execute a few particular tasks on main thread only like proxy creation, etc. so in such a scenario, I have to communicate with the main thread and need to post that particular task on the main thread. I have designed LoopingThread.cpp as mentioned below and communicating with the main for posting tasks on that:
LoopingThread.cpp:
#include <iostream>
#include "loopingThread.hpp"
using namespace std;
LoopingThread::LoopingThread() : thread(nullptr), scheduledCallbacks() {
}
LoopingThread::~LoopingThread() {
if (this->thread) {
delete this->thread;
}
}
void LoopingThread::runCallbacks() {
this->callbacksMutex.lock();
if (this->scheduledCallbacks.size() > 0) {
std::thread::id threadID = std::this_thread::get_id();
std::cout<<"inside runCallback()threadId:"<<threadID<<std::endl;
// This is to allow for new callbacks to be scheduled from within a callback
std::vector<std::function<void()>> currentCallbacks = std::move(this->scheduledCallbacks);
this->scheduledCallbacks.clear();
this->callbacksMutex.unlock();
for (auto callback : currentCallbacks) {
//callback();
//this->callback();
int id = 1;
this->shared_func(id);
}
} else {
this->callbacksMutex.unlock();
}
}
void LoopingThread::shared_func(int id)
{
std::thread::id run_threadID = std::this_thread::get_id();
std::cout<<"shared_func: "<<run_threadID<<std::endl;
this->callbacksMutex.lock();
if (id == 0)
std::cout<<"calling from main,id: "<<id<<std::endl;
else if (id == 1)
std::cout<<"calling from child,id: "<<id<<std::endl;
this->callbacksMutex.unlock();
}
void LoopingThread::run() {
std::thread::id run_threadID = std::this_thread::get_id();
std::cout<<"Child_run_threadID: "<<run_threadID<<std::endl;
for (;;) {
this->runCallbacks();
// Run the tick
if (!this->tick()) {
std::cout<<"Run the tick"<<std::endl;
break;
}
}
// Run pending callbacks, this might result in an infinite loop if there are more
// callbacks scheduled from within scheduled callbacks
this->callbacksMutex.lock();
while (this->scheduledCallbacks.size() > 0) {
std::cout<<"inside scheduledCallbacks.size() > 0"<<std::endl;
this->callbacksMutex.unlock();
this->runCallbacks();
this->callbacksMutex.lock();
}
this->callbacksMutex.unlock();
}
void LoopingThread::scheduleCallback(std::function<void()> callback) {
std::cout<<"inside schedulecallback"<<std::endl;
this->callbacksMutex.lock();
this->scheduledCallbacks.push_back(callback);
this->callbacksMutex.unlock();
}
void LoopingThread::start() {
if (!this->thread) {
this->thread = new std::thread(&LoopingThread::run, this);
//std::thread::id threadID = std::this_thread::get_id();
//std::cout<<"creating thread: "<<threadID<<std::endl;
}
}
void LoopingThread::join() {
if (this->thread && this->thread->joinable()) {
this->thread->join();
std::cout<<"joining thread"<<std::endl;
}
}
**main.cpp:**
#include <thread>
#include <chrono>
#include <iostream>
#include <mutex>
#include <string>
#include "loopingThread.hpp"
using namespace std;
std::mutex stdoutMutex;
// Example usage of LoopingThread with a classic MainThread:
class MainThread : public LoopingThread {
private:
MainThread();
public:
virtual ~MainThread();
static MainThread& getInstance();
virtual bool tick();
};
MainThread::MainThread() {}
MainThread::~MainThread() {}
MainThread& MainThread::getInstance() {
// Provide a global instance
static MainThread instance;
return instance;
}
bool MainThread::tick() {
// std::cout<<"main thread:"<<threadID<<std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
stdoutMutex.lock();
std::cout << "tick" << std::endl;
stdoutMutex.unlock();
// Return false to stop this thread
return true;
}
void doLongAsyncTask() {
std::thread longTask([] () {
stdoutMutex.lock();
std::cout << "Beginning long task..." <<std::endl;
stdoutMutex.unlock();
std::this_thread::sleep_for(std::chrono::seconds(2));
stdoutMutex.lock();
std::cout << "Long task finished!" << std::endl;
stdoutMutex.unlock();
MainThread::getInstance().scheduleCallback([] () {
stdoutMutex.lock();
std::cout << "This is called within the main thread!" << std::endl <<
"No need to worry about thread safety or " <<
"race conditions here" << std::endl;
stdoutMutex.unlock();
});
});
longTask.detach();
}
int main() {
doLongAsyncTask();
MainThread::getInstance().start();
MainThread::getInstance().join();
MainThread::getInstance().run();
}
Now suppose child thread receives any task of creating proxy then It needs to post that task back to the main thread. How to achieve this scenario?
I'm trying to implement an multi-thread job, a producer and a consumer, and basically what I want to do is, when consumer finishes the data, it notifies the producer so that producer provides new data.
The tricky part is, in my current impl, producer and consumer both notifies each other and waits for each other, I don't know how to implement this part correctly.
For example, see the code below,
mutex m;
condition_variable cv;
vector<int> Q; // this is the queue the consumer will consume
vector<int> Q_buf; // this is a buffer Q into which producer will fill new data directly
// consumer
void consume() {
while (1) {
if (Q.size() == 0) { // when consumer finishes data
unique_lock<mutex> lk(m);
// how to notify producer to fill up the Q?
...
cv.wait(lk);
}
// for-loop to process the elems in Q
...
}
}
// producer
void produce() {
while (1) {
// for-loop to fill up Q_buf
...
// once Q_buf is fully filled, wait until consumer asks to give it a full Q
unique_lock<mutex> lk(m);
cv.wait(lk);
Q.swap(Q_buf); // replace the empty Q with the full Q_buf
cv.notify_one();
}
}
I'm not sure this the above code using mutex and condition_variable is the right way to implement my idea,
please give me some advice!
The code incorrectly assumes that vector<int>::size() and vector<int>::swap() are atomic. They are not.
Also, spurious wakeups must be handled by a while loop (or another cv::wait overload).
Fixes:
mutex m;
condition_variable cv;
vector<int> Q;
// consumer
void consume() {
while(1) {
// Get the new elements.
vector<int> new_elements;
{
unique_lock<mutex> lk(m);
while(Q.empty())
cv.wait(lk);
new_elements.swap(Q);
}
// for-loop to process the elems in new_elements
}
}
// producer
void produce() {
while(1) {
vector<int> new_elements;
// for-loop to fill up new_elements
// publish new_elements
{
unique_lock<mutex> lk(m);
Q.insert(Q.end(), new_elements.begin(), new_elements.end());
cv.notify_one();
}
}
}
Maybe that is close to what you want to achive. I used 2 conditional variables to notify producers and consumers between each other and introduced variable denoting which turn is now:
#include <ctime>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <queue>
#include <thread>
template<typename T>
class ReaderWriter {
private:
std::vector<std::thread> readers;
std::vector<std::thread> writers;
std::condition_variable readerCv, writerCv;
std::queue<T> data;
std::mutex readerMutex, writerMutex;
size_t noReaders, noWriters;
enum class Turn { WRITER_TURN, READER_TURN };
Turn turn;
void reader() {
while (1) {
{
std::unique_lock<std::mutex> lk(readerMutex);
while (turn != Turn::READER_TURN) {
readerCv.wait(lk);
}
std::cout << "Thread : " << std::this_thread::get_id() << " consumed " << data.front() << std::endl;
data.pop();
if (data.empty()) {
turn = Turn::WRITER_TURN;
writerCv.notify_one();
}
}
}
}
void writer() {
while (1) {
{
std::unique_lock<std::mutex> lk(writerMutex);
while (turn != Turn::WRITER_TURN) {
writerCv.wait(lk);
}
srand(time(NULL));
int random_number = std::rand();
data.push(random_number);
std::cout << "Thread : " << std::this_thread::get_id() << " produced " << random_number << std::endl;
turn = Turn::READER_TURN;
}
readerCv.notify_one();
}
}
public:
ReaderWriter(size_t noReadersArg, size_t noWritersArg) : noReaders(noReadersArg), noWriters(noWritersArg), turn(ReaderWriter::Turn::WRITER_TURN) {
}
void run() {
int noReadersArg = noReaders, noWritersArg = noWriters;
while (noReadersArg--) {
readers.emplace_back(&ReaderWriter::reader, this);
}
while (noWritersArg--) {
writers.emplace_back(&ReaderWriter::writer, this);
}
}
~ReaderWriter() {
for (auto& r : readers) {
r.join();
}
for (auto& w : writers) {
w.join();
}
}
};
int main() {
ReaderWriter<int> rw(5, 5);
rw.run();
}
Here's a code snippet. Since the worker treads are already synchronized, requirement of two buffers is ruled out. So a simple queue is used to simulate the scenario:
#include "conio.h"
#include <iostream>
#include <thread>
#include <mutex>
#include <queue>
#include <atomic>
#include <condition_variable>
using namespace std;
enum state_t{ READ = 0, WRITE = 1 };
mutex mu;
condition_variable cv;
atomic<bool> running;
queue<int> buffer;
atomic<state_t> state;
void generate_test_data()
{
const int times = 5;
static int data = 0;
for (int i = 0; i < times; i++) {
data = (data++) % 100;
buffer.push(data);
}
}
void ProducerThread() {
while (running) {
unique_lock<mutex> lock(mu);
cv.wait(lock, []() { return !running || state == WRITE; });
if (!running) return;
generate_test_data(); //producing here
lock.unlock();
//notify consumer to start consuming
state = READ;
cv.notify_one();
}
}
void ConsumerThread() {
while (running) {
unique_lock<mutex> lock(mu);
cv.wait(lock, []() { return !running || state == READ; });
if (!running) return;
while (!buffer.empty()) {
auto data = buffer.front(); //consuming here
buffer.pop();
cout << data << " \n";
}
//notify producer to start producing
if (buffer.empty()) {
state = WRITE;
cv.notify_one();
}
}
}
int main(){
running = true;
thread producer = thread([]() { ProducerThread(); });
thread consumer = thread([]() { ConsumerThread(); });
//simulating gui thread
while (!getch()){
}
running = false;
producer.join();
consumer.join();
}
Not a complete answer, though I think two condition variables could be helpful, one named buffer_empty that the producer thread will wait on, and another named buffer_filled that the consumer thread will wait on. Number of mutexes, how to loop, and so on I cannot comment on, since I'm not sure about the details myself.
Accesses to shared variables should only be done while holding the
mutex that protects it
condition_variable::wait should check a condition.
The condition should be a shared variable protected by the mutex that you pass to condition_variable::wait.
The way to check the condition is to wrap the call to wait in a while loop or use the 2-argument overload of wait (which is
equivalent to the while-loop version)
Note: These rules aren't strictly necessary if you truly understand what the hardware is doing. However, these problems get complicated quickly when with simple data structures, and it will be easier to prove that your algorithm is working correctly if you follow them.
Your Q and Q_buf are shared variables. Due to Rule 1, I would prefer to have them as local variables declared in the function that uses them (consume() and produce(), respectively). There will be 1 shared buffer that will be protected by a mutex. The producer will add to its local buffer. When that buffer is full, it acquires the mutex and pushes the local buffer to the shared buffer. It then waits for the consumer to accept this buffer before producing more data.
The consumer waits for this shared buffer to "arrive", then it acquires the mutex and replaces its empty local buffer with the shared buffer. Then it signals to the producer that the buffer has been accepted so it knows to start producing again.
Semantically, I don't see a reason to use swap over move, since in every case one of the containers is empty anyway. Maybe you want to use swap because you know something about the underlying memory. You can use whichever you want and it will be fast and work the same (at least algorithmically).
This problem can be done with 1 condition variable, but it may be a little easier to think about if you use 2.
Here's what I came up with. Tested on Visual Studio 2017 (15.6.7) and GCC 5.4.0. I don't need to be credited or anything (it's such a simple piece), but legally I have to say that I offer no warranties whatsoever.
#include <thread>
#include <vector>
#include <mutex>
#include <condition_variable>
#include <chrono>
std::vector<int> g_deliveryBuffer;
bool g_quit = false;
std::mutex g_mutex; // protects g_deliveryBuffer and g_quit
std::condition_variable g_producerDeliver;
std::condition_variable g_consumerAccepted;
// consumer
void consume()
{
// local buffer
std::vector<int> consumerBuffer;
while (true)
{
if (consumerBuffer.empty())
{
std::unique_lock<std::mutex> lock(g_mutex);
while (g_deliveryBuffer.empty() && !g_quit) // if we beat the producer, wait for them to push to the deliverybuffer
g_producerDeliver.wait(lock);
if (g_quit)
break;
consumerBuffer = std::move(g_deliveryBuffer); // get the buffer
}
g_consumerAccepted.notify_one(); // notify the producer that the buffer has been accepted
// for-loop to process the elems in Q
// ...
consumerBuffer.clear();
// ...
}
}
// producer
void produce()
{
std::vector<int> producerBuffer;
while (true)
{
// for-loop to fill up Q_buf
// ...
producerBuffer = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
// ...
// once Q_buf is fully filled, wait until consumer asks to give it a full Q
{ // scope is for lock
std::unique_lock<std::mutex> lock(g_mutex);
g_deliveryBuffer = std::move(producerBuffer); // ok to push to deliverybuffer. it is guaranteed to be empty
g_producerDeliver.notify_one();
while (!g_deliveryBuffer.empty() && !g_quit)
g_consumerAccepted.wait(lock); // wait for consumer to signal for more data
if (g_quit)
break;
// We will never reach this point if the buffer is not empty.
}
}
}
int main()
{
// spawn threads
std::thread consumerThread(consume);
std::thread producerThread(produce);
// for for 5 seconds
std::this_thread::sleep_for(std::chrono::seconds(5));
// signal that it's time to quit
{
std::lock_guard<std::mutex> lock(g_mutex);
g_quit = true;
}
// one of the threads may be sleeping
g_consumerAccepted.notify_one();
g_producerDeliver.notify_one();
consumerThread.join();
producerThread.join();
return 0;
}
I have an application with 2 QThreads which behave like it in the pseudocode below (the semaphores are of type QSemaphore):
Thread1 {
print("about to wait on semaphore 1");
sem1.acquire(1);
print("finished waiting on semaphore 1");
sem2.release(1);
}
Thread2 {
print("signaling semaphore 1");
sem1.release(1);
print("about to wait on semaphore 2");
sem2.acquire(1);
}
The issue is that the first thread does NOT wake up when the first semaphore is signalled, i.e. the application produces the following output:
about to wait on semaphore 1
signaling semaphore 1
about to wait on semaphore 2
And that's it. The first thread no longer wakes up.
Now I change the first thread to do the following:
Thread1 {
print("about to wait on semaphore 1");
while (!sem1.tryAcquire(1, 200));
print("finished waiting on semaphore 1");
sem2.release(1);
}
In this case the first thread sleeps for at most 200ms before it tries to acquire the semaphore again. Now I get the following error:
QWaitCondition::wait(): mutex unlock failure: Invalid argument
No other mutexes or other synchronisation primitives are used by the application. What could be the issue?
Update:
I've removed the Semaphores and replaced each with a QWaitCondition and a QMutex and now it works just fine. I didn't make any other changes and I still don't know why the version with semaphores was incorrect. They were both initialised to 0.
Probably you do something wrong somewhere else (e.g., semaphore initialization code).
The following example compiles and runs (gcc).
threads.h:
#pragma once
#include <QThread>
class Thread1 : public QThread
{
protected:
virtual void run();
};
class Thread2 : public QThread
{
protected:
virtual void run();
};
threads.cpp:
#include "threads.h"
#include <QSemaphore>
#include <iostream>
namespace
{
QSemaphore sem1, sem2;
}
void Thread1::run()
{
std::cout << "about to wait on semaphore 1\n";
sem1.acquire(1);
//while (!sem1.tryAcquire(1, 200)); //works too
std::cout << "finished waiting on semaphore 1\n";
sem2.release(1);
}
void Thread2::run()
{
std::cout << "signaling semaphore 1\n";
sem1.release(1);
std::cout << "about to wait on semaphore 2\n";
sem2.acquire(1);
}
main.cpp:
#include "threads.h"
#include <iostream>
int main(int argc, char *argv[])
{
Thread1 t1;
Thread2 t2;
t1.start();
t2.start();
t1.wait();
t2.wait();
std::cout << "Success\n";
}
possible output:
signaling semaphore 1
about to wait on semaphore 2
about to wait on semaphore 1
finished waiting on semaphore 1
Success
Is there a way to start two (or more) C++11 threads and join() the first one that is finished?
An example scenario:
#include <iostream>
#include <thread>
using namespace std;
void prepare_item1() {std::cout << "Preparing 1" << std::endl;}
void consume_item1() {std::cout << "Consuming 1" << std::endl;}
void prepare_item2() {std::cout << "Preparing 2" << std::endl;}
void consume_item2() {std::cout << "Consuming 2" << std::endl;}
int main()
{
std::thread t1(prepare_item1);
std::thread t2(prepare_item2);
t1.join();
consume_item1();
t2.join();
consume_item2();
return 0;
}
I would have liked to do something like that instead:
int main()
{
std::thread t1(prepare_item1);
std::thread t2(prepare_item2);
finished_id=join_any(t1,t2)
if (finished_id==1)
{
consume_item1();
...
}
else if (finished_id==2)
{
consume_item2();
...
}
return 0;
}
Also, I would like the solution to be blocking, similar to the t.join() function.
Note: The real reason I need this is that I have two different blocking functions from which I receive commands, and whenever any of them is ready I would like to process the first command that arrives and continue to the next one when it is done. (sequential processing of commands from two parallel sources)
Thanks!
Here is a thread-safe multi-producer multi-consumer queue:
template<class T>
struct safe_queue {
std::deque<T> data;
std::atomic<bool> abort_flag = false;
std::mutex guard;
std::condition_variable signal;
template<class...Args>
void send( Args&&...args ) {
{
std::unique_lock<std::mutex> l(guard);
data.emplace_back(std::forward<Args>(args)...);
}
signal.notify_one();
}
void abort() {
abort_flag = true; // 1a
{ std::unique_lock<std::mutex>{guard}; }
signal.notify_all(); // 1b
}
std::experimental::optional<T> get() {
std::unique_lock<std::mutex> l(guard);
signal.wait( l, [this]()->bool{ // 2b
return !data.empty() || abort_flag.load(); // 2c
});
if (abort_flag.load()) return {};
T retval = std::move(data.front());
data.pop_front();
return retval;
}
};
have the threads shove data into the queue, and the main thread do a .get() on it.
If abort() is called, all waiting threads are woken up with an "empty" value from .get().
It uses std::experimental::optional, but you can replace that with something else (throw on abort? Whatever).
Code modified slightly from this other answer. Note that I think the other answer has some errors in it, which I corrected above, and attempts to solve a different problem.
The message you send could be the id of the thread that is ready to be waited upon, for example, or the work it has completed, or whatever.