How to “multithread” C code

后端 未结 12 1800
暗喜
暗喜 2020-12-02 09:30

I have a number crunching application written in C. It is kind of a main loop that for each value calls, for increasing values of \"i\", a function that performs some calcul

12条回答
  •  误落风尘
    2020-12-02 09:56

    C11 threads in glibc 2.28.

    Tested in Ubuntu 18.04 (glibc 2.27) by compiling glibc from source: Multiple glibc libraries on a single host

    Example from: https://en.cppreference.com/w/c/language/atomic

    #include 
    #include 
    #include 
    
    atomic_int acnt;
    int cnt;
    
    int f(void* thr_data)
    {
        for(int n = 0; n < 1000; ++n) {
            ++cnt;
            ++acnt;
            // for this example, relaxed memory order is sufficient, e.g.
            // atomic_fetch_add_explicit(&acnt, 1, memory_order_relaxed);
        }
        return 0;
    }
    
    int main(void)
    {
        thrd_t thr[10];
        for(int n = 0; n < 10; ++n)
            thrd_create(&thr[n], f, NULL);
        for(int n = 0; n < 10; ++n)
            thrd_join(thr[n], NULL);
    
        printf("The atomic counter is %u\n", acnt);
        printf("The non-atomic counter is %u\n", cnt);
    }
    

    GitHub upstream.

    Compile and run:

    gcc -std=c11 main.c -pthread
    ./a.out
    

    Possible output:

    The atomic counter is 10000
    The non-atomic counter is 8644
    

    The non-atomic counter is very likely to be smaller than the atomic one due to racy access across threads to the non atomic variable.

    TODO: disassemble and see what ++acnt; compiles to.

    POSIX threads

    #define _XOPEN_SOURCE 700
    #include 
    #include 
    #include 
    
    enum CONSTANTS {
        NUM_THREADS = 1000,
        NUM_ITERS = 1000
    };
    
    int global = 0;
    int fail = 0;
    pthread_mutex_t main_thread_mutex = PTHREAD_MUTEX_INITIALIZER;
    
    void* main_thread(void *arg) {
        int i;
        for (i = 0; i < NUM_ITERS; ++i) {
            if (!fail)
                pthread_mutex_lock(&main_thread_mutex);
            global++;
            if (!fail)
                pthread_mutex_unlock(&main_thread_mutex);
        }
        return NULL;
    }
    
    int main(int argc, char **argv) {
        pthread_t threads[NUM_THREADS];
        int i;
        fail = argc > 1;
        for (i = 0; i < NUM_THREADS; ++i)
            pthread_create(&threads[i], NULL, main_thread, NULL);
        for (i = 0; i < NUM_THREADS; ++i)
            pthread_join(threads[i], NULL);
        assert(global == NUM_THREADS * NUM_ITERS);
        return EXIT_SUCCESS;
    }
    

    Compile and run:

    gcc -std=c99 pthread_mutex.c -pthread
    ./a.out
    ./a.out 1
    

    The first run works fine, the second fails due to missing synchronization.

    Tested on Ubuntu 18.04. GitHub upstream.

提交回复
热议问题