#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!
#endif

#include <assert.h>
#include <stdio.h>
#include <threads.h>
#include <pthread.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
{
    pthread_spinlock_t lock;
    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)
    {
        pthread_spin_lock(&data->lock);

        data->value += x;

        pthread_spin_unlock(&data->lock);
    }

    return 0;
}

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

    struct WorkData data =
    {
        .value = 0,
        .step_value = 2,
        .proc_times = 100000000,
    };

    int err = pthread_spin_init(&data.lock, PTHREAD_PROCESS_PRIVATE);
    assert( err == 0 );

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

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

    for(int i = 0; i < thrd_num; ++i)
    {
        int res;
        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",
        data.value,
        thrd_num * data.step_value * data.proc_times,
        end_time - begin_time);

    err = pthread_spin_destroy(&data.lock);
    assert( err == 0 );

    return 0;
}
