// 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;

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

using namespace boost;
using namespace boost::chrono;

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 some work between get and set
    string s = d->GetS();
    this_thread::sleep_for(microseconds(1));
    d->SetS(s + "X");
}

typedef thread *thread_ptr;

void test(int njobs, int nthreads)
{
    // setup data
    Data *d = new Data("");
    // process with shared data
    for(int i = 0; i < njobs / nthreads; i++)
    {
        // create and start threads
        thread_ptr *t = new thread_ptr[nthreads];
        for(int j = 0; j < nthreads; j++)
        {
            t[j] = new thread(run, d);
        }
        // wait for threads to complete
        for(int j = 0; j < nthreads; j++)
        {
            t[j]->join();
            delete t[j];
        }
        delete[] t;
    }
    cout << nthreads << " threads : expected = " << njobs << ", actual = " << d->GetS().length() << endl;;
}

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

