// g++ pass.loop.var.cpp -lpthread
#include <fstream>
#include <iostream>
#include <pthread.h> /* thread stuff */
#include <unistd.h>  /* usleep */

pthread_mutex_t print_mutex;
int thread_count = 0;

struct Arguments {
    int i;
};

void* cell1( void * p )
{
    int arg = *reinterpret_cast<int*>( p );
    //usleep( 100 ); // fake some work time
    pthread_mutex_lock( &print_mutex );
    std::cout << "Thread " << arg << std::endl;
    pthread_mutex_unlock( &print_mutex );
}

void* cell2( void * p )
{
    Arguments arg = *reinterpret_cast<Arguments*>( p );
    //usleep( 100 ); // fake some work time
    pthread_mutex_lock( &print_mutex );
    std::cout << "Thread " << arg.i << std::endl;
    pthread_mutex_unlock( &print_mutex );
}

int main( int argc, char ** argv ) 
{
    int const size = 10;
    // storage for threads
    pthread_t threads_id[size];

	pthread_mutex_init( &print_mutex, 0 );
	
    // storage for arguments
    Arguments args[size];

    // pre-allocate all thread arguments
    for ( int i=0; i<size; ++i ) { 
        args[i].i = i;
    }

#define GOOD

#ifdef GOOD
    for ( int i=0; i<size; ++i ) {
        pthread_mutex_lock( &print_mutex );
        std::cout << "Create thread " << i << std::endl;
        pthread_mutex_unlock( &print_mutex );
        // each thread reads from a different location
        pthread_create( &threads_id[i], 0, cell2, &args[i] );
    }
#else
    for ( int i=0; i<size; ++i ) {
        pthread_mutex_lock( &print_mutex );
        std::cout << "Create thread " << i << std::endl;
        pthread_mutex_unlock( &print_mutex );
        // all threads read from the same i, i may change by the time thread does the read
        pthread_create( &threads_id[i], 0, cell1, &i );
    }
#endif

    for ( int i=0; i<size; ++i ) {
        pthread_join( threads_id[i], 0 );
    }
}