/* 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 <windows.h>
#include <process.h>

#define MAX_STR_LEN 8192

struct data {
    char s[MAX_STR_LEN];
};

static CRITICAL_SECTION cs;

unsigned int __stdcall run(void *p)
{
    struct data *d;
    char s[MAX_STR_LEN];
    d = p;
    EnterCriticalSection(&cs);
    strcpy(s, d->s);
    Sleep(0);
    strcpy(d->s, s);
    strcat(d->s, "X");
    LeaveCriticalSection(&cs);
    return 0;
}

void test(int njobs, int nthreads)
{
    struct data d;
    HANDLE *t;
    int i, j;
    /* setup data */
    strcpy(d.s, "");
    /* process with shared data */
    InitializeCriticalSection(&cs);
    for(i = 0; i < njobs / nthreads; i++)
    {
        /* create and start threads */
        t = malloc(nthreads * sizeof(HANDLE));
        for(j = 0; j < nthreads; j++)
        {
            t[j] = (HANDLE)_beginthreadex(NULL, 0, run, &d, 0, NULL);
        }
        /* wait for threads to complete */
        for(j = 0; j < nthreads; j++)
        {
            WaitForSingleObject(t[j], INFINITE);
            CloseHandle(t[j]);
        }
        free(t);
    }
    DeleteCriticalSection(&cs);
    printf("%d threads : expected = %d, actual = %d\n", nthreads, njobs, (int)strlen(d.s));
}

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