#if __STDC_VERSION__ < 201112L
#   error Needs a C compiler which support the C11 standard or later!
#elif defined(__STDC_NO_THREADS__)
#   error Needs the C compiler and its runtime library support the C11 thread functions!
#elif defined(__STDC_NO_ATOMICS__)
#   error Needs the C compiler have the atomic operations support!
#endif

#include <assert.h>
#include <stdio.h>
#include <threads.h>
#include <stdatomic.h>

#ifdef _WIN32
#   include <windows.h>
#else
#   include <unistd.h>
#endif

static
unsigned GetMsTime(void)
{
#ifdef _WIN32
    return GetTickCount();
#else
    struct timespec ts;
    int err = clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
    assert( err == 0 );

    return ts.tv_sec * 1000 + ts.tv_nsec / (1000*1000);
#endif
}

struct WorkData
{
    atomic_int value;
    int step_value;
    int proc_times;
};

static
int ThrdFunc(struct WorkData *data)
{
    int n = data->proc_times;
    int x = data->step_value;

    for(int i = 0; i < n; ++i)
        atomic_fetch_add(&data->value, x);

    return 0;
}

int main(int argc, char *argv[])
{
    unsigned begin_time = GetMsTime();

    struct WorkData data = { .step_value = 2, .proc_times = 100000000 };
    atomic_init(&data.value, 0);

    static const int thrd_num = 4;
    thrd_t thrd_list[thrd_num];

    for(int i = 0; i < thrd_num; ++i)
    {
        int err = thrd_create(&thrd_list[i], (int(*)(void*)) ThrdFunc, &data);
        assert( err == thrd_success );
    }

    for(int i = 0; i < thrd_num; ++i)
    {
        int res;
        int err = thrd_join(thrd_list[i], &res);
        assert( err == thrd_success && res == 0 );
    }

    unsigned end_time = GetMsTime();
    printf("Finished, value=%d/%d, spend=%u\n",
        atomic_load(&data.value),
        thrd_num * data.step_value * data.proc_times,
        end_time - begin_time);

    return 0;
}
