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

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

static int global_variable_0 = 0;
static int global_variable_1 = 0;
static int global_variable_2 = 0;
static int global_variable_3 = 0;

static
void SleepMs(unsigned ms)
{
#ifdef _WIN32
    Sleep(ms);
#else
    usleep( 1000 * ms );
#endif
}

static
int ThrdFunc1(void *arg)
{
    for(int i = 0; i < 17; ++i)
    {
        global_variable_1++;
        printf("In function 1: variables = %d, %d, %d, %d\n",
            global_variable_0, global_variable_1, global_variable_2, global_variable_3);
        SleepMs(300);
    }

    return 0;
}

static
int ThrdFunc2(void *arg)
{
    for(int i = 0; i < 10; ++i)
    {
        global_variable_2++;
        printf("In function 2: variables = %d, %d, %d, %d\n",
            global_variable_0, global_variable_1, global_variable_2, global_variable_3);
        SleepMs(500);
    }

    return 0;
}

static
int ThrdFunc3(void *arg)
{
    for(int i = 0; i < 7; ++i)
    {
        global_variable_3++;
        printf("In function 3: variables = %d, %d, %d, %d\n",
            global_variable_0, global_variable_1, global_variable_2, global_variable_3);
        SleepMs(700);
    }

    return 0;
}

int main(int argc, char *argv[])
{
    // 建立並啟動數個執行緒

    thrd_t thrd1;
    int err = thrd_create(&thrd1, ThrdFunc1, NULL);
    assert( err == thrd_success );

    thrd_t thrd2;
    err = thrd_create(&thrd2, ThrdFunc2, NULL);
    assert( err == thrd_success );

    thrd_t thrd3;
    err = thrd_create(&thrd3, ThrdFunc3, NULL);
    assert( err == thrd_success );

    // 在被我們建立的執行緒們正在工作的同時，原本的這個主執行緒仍然可以繼續進行它自己的工作

    for(int i = 0; i < 5; ++i)
    {
        global_variable_0++;
        printf("In function main: variables = %d, %d, %d, %d\n",
            global_variable_0, global_variable_1, global_variable_2, global_variable_3);
        SleepMs(1000);
    }

    // 關閉所有我們建立的執行緒資源

    err = thrd_detach(thrd1);       // 關閉一個執行緒資源，但不會等待它結束才返回，相當於放生了這個執行緒
    assert( err == thrd_success );

    int res;
    err = thrd_join(thrd2, &res);   // 等待一個執行緒的執行，並在執行緒結束後才關閉它
    assert( err == thrd_success && res == 0 );

    err = thrd_join(thrd3, &res);   // 等待一個執行緒的執行，並在執行緒結束後才關閉它
    assert( err == thrd_success && res == 0 );

    return 0;
}
