// Collection of code snippets by Arne Vajhøj 
// (from articles on eksperten.dk / vajhoej.dk written sometime between 2004 and now) 
#include <iostream>
#include <iomanip>
#include <string>

//using namespace std; // std may conflict with boost for newer C++
using std::string;
using std::cout;
using std::endl;
using std::fixed;
using std::setprecision;

#include <boost/thread.hpp>
#include <boost/chrono.hpp>
#include <boost/asio.hpp>

using namespace boost;
using namespace boost::chrono;
using namespace boost::asio;

class Data
{
private:
    string s;
public:
    Data(string s);
    string GetS();
    void SetS(string s);
};

Data::Data(string s)
{
    this->s = s;
}

string Data::GetS()
{
    return s;
}

void Data::SetS(string s)
{
    this->s = s;
}

typedef Data *DataPtr;

void run(Data *d)
{
    // simulate a lot of work that takes 0.1 second
    string s = d->GetS();
    this_thread::sleep_for(milliseconds(100));
    d->SetS(s + "X");
}

void test(int njobs, int nthreads)
{
    // setup data
    DataPtr *d = new DataPtr[njobs];
    for(int i = 0; i < njobs; i++)
    {
        d[i] = new Data("X");
    }
    
    thread_pool pool(nthreads);
    // submit jobs
    time_point<system_clock> t1 = system_clock::now();
    for(int i = 0; i < njobs; i++)
    {
        post(pool, bind(run, d[i]));
    }
    pool.join();
    time_point<system_clock> t2 = system_clock::now();
    duration<double> dt = t2 - t1;
    cout << njobs << " jobs executing in " << nthreads << " threads : " << fixed << setprecision(1) << dt.count() << " seconds" << endl;
    // check data
    for(int i = 0; i < njobs; i++)
    {
        if(d[i]->GetS() != "XX") cout << "Ooops" << endl;
        delete d[i];
    }
    delete[] d;
}

int main()
{
    test(256, 1);
    test(256, 2);
    test(256, 4);
    test(256, 8);
    test(256, 16);
    test(256, 32);
    test(256, 64);
    return 0;
}

