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

#include <unistd.h>
#include <pthread.h>

#define MAX_STR_LEN 1024

struct data {
    char s[MAX_STR_LEN];
};

void *run(void *p)
{
    struct data *d;
    char s[MAX_STR_LEN];
    d = p;
    /* simulate a lot of work that takes 0.1 second */
    strcpy(s, d->s);
    usleep(100000);
    strcpy(d->s, s);
    strcat(d->s, "X");
    return NULL;
}

void test(int njobs, int nthreads)
{
    struct data *d;
    pthread_t *t;
    time_t t1, t2;
    int i, j, k;
    void *p;
    /* setup data */
    d = malloc(njobs * sizeof(struct data));
    for(i = 0; i < njobs; i++)
    {
        strcpy(d[i].s, "X");
    }
    /* process */
    t1 = time(NULL);
    k = 0;
    for(i = 0; i < njobs / nthreads; i++)
    {
        /* create and start threads */
        t = malloc(nthreads * sizeof(pthread_t));
        for(j = 0; j < nthreads; j++)
        {
            pthread_create(&t[j], NULL, run, &d[k]);
            k++;
        }
        /* wait for threads to complete */
        for(j = 0; j < nthreads; j++)
        {
            pthread_join(t[j], &p);
        }
        free(t);
    }
    t2 = time(NULL);
    printf("%d jobs executing in %d threads : %d seconds\n", njobs, nthreads, (int)(t2 - t1));
    /* check data */
    for(i = 0; i < njobs; i++)
    {
        if(strcmp(d[i].s, "XX") != 0) printf("Ooops\n");
    }
    free(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;
}
