This code is supposed to asynchronously load a queue from a generating function.
#include <queue>
#include <functional>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <iostream>
#include <stdexcept>
using namespace std;
template <typename Container>
struct LoadAsync {
LoadAsync( size_t queue_size, function<Container()> f )
: find_next( f ), size( queue_size ),
worker_thread( &LoadAsync<Container>::worker_thread_function, this )
{
// first, build the basics
unique_lock<mutex> lk( m );
cv_init.wait( lk, [this] { return this->qued.size() >= this->size; } );
}
LoadAsync( const LoadAsync& ) = delete;
void worker_thread_function()
{
while ( true ) {
unique_lock<mutex> lk( m );
cv.wait( lk, [this] { return this->qued.size() < this->size; } );
while ( this->qued.size() < this->size ) {
try {
qued.emplace( find_next() );
} catch (domain_error) {
this->size--;
}
}
lk.unlock();
cv_init.notify_one();
}
}
Container pop_front()
{
unique_lock<mutex> lk( m );
cv_init.wait( lk, [this] { return this->qued.size() >= this->size; } );
if (this->qued.size() == 0)
throw out_of_range("out of range");
auto front = move( qued.front() );
qued.pop();
lk.unlock();
cv.notify_one();
return front;
}
private:
size_t size;
queue<Container> qued;
function<Container()> find_next;
thread worker_thread;
mutex m;
condition_variable cv;
condition_variable cv_init;
};
int main()
{
auto func = []() {
static int which = 1;
if ( which < 10 )
return which++;
else
throw domain_error("out of range");
};
LoadAsync<int> la( 3, func );
for ( int i = 0; i < 11; ++i ) cout << la.pop_front() << endl;
}
Is this a good approach? Are there any gotchas here in using condition_variables? Are there any long bottlenecks here? Is waiting on a condition variable an immediate thing?