1. 程式人生 > 其它 >C語言執行緒安全問題

C語言執行緒安全問題

執行緒安全問題

#include <stdio.h>
#include <tinycthread.h>
#include <io_utils.h>

int count = 0;
int Counter(void*arg)
{
    for(int i = 0;i<100000;i++)
    {
        count++;
        /*
         * int temp = count;
         * count=temp+1;
         * return temp;
         * */
    }
    return 0;
}

int main()
{
    thrd_t t1;
    thrd_t t2;

    thrd_create(&t1,Counter,NULL);
    thrd_create(&t2,Counter,NULL);

    thrd_join(t1,NULL);
    thrd_join(t2,NULL);
    PRINT_INT(count);

    return 0;
}
  • 執行結果不是所要值原因是count++在併發時產生衝突

執行緒安全的產生

  • 對共享資源進行非原子的訪問
  • 不同執行緒之間程式碼可見性問題
  • 執行緒內部程式碼編譯時的重排序問題

解決方法一 消除副作用

#include <stdio.h>
#include <tinycthread.h>
#include <io_utils.h>


int Counter(void*arg)
{
    int count = 0;
    for(int i = 0;i<100000;i++)
    {
        count++;
    }
    return count;
}

int main()
{
    thrd_t t1;
    thrd_t t2;

    thrd_create(&t1,Counter,NULL);
    thrd_create(&t2,Counter,NULL);
    int count = 0;
    int result = 0;

    thrd_join(t1,&result);
    count+=result;

    thrd_join(t2,&result);
    count+=result;

    PRINT_INT(count);

    return 0;
}

解決方法二 原子型別

#include<stdio.h>
#include <tinycthread.h>
#include <io_utils.h>
#include <stdatomic.h>

atomic_int count = 0;   //設定原子型別
int Counter(void*arg)
{
    for(int i = 0;i<100000;i++)
    {
        count++;
    }
    return 0;
}

int main()
{
    thrd_t t1;
    thrd_t t2;

    thrd_create(&t1,Counter,NULL);
    thrd_create(&t2,Counter,NULL);

    thrd_join(t1,NULL);
    thrd_join(t2,NULL);
    PRINT_INT(count);

    return 0;

}

解決方法三 原子操作

#include<stdio.h>
#include <tinycthread.h>
#include <io_utils.h>
#include <stdatomic.h>

atomic_flag resume_flag = ATOMIC_FLAG_INIT;
int PrintNumber(void*arg)
{
    int current = 0;
    while(atomic_flag_test_and_set(&resume_flag))
    {
        current++;
        PRINT_INT(current);
        thrd_sleep(&(struct timespec){.tv_sec=1},NULL);
    }
    return current;
}
int main()
{
    atomic_flag_test_and_set(&resume_flag);
    thrd_t t;
    thrd_create(&t,PrintNumber,NULL);
    thrd_sleep(&(struct timespec){.tv_sec=5},NULL);
    atomic_flag_clear(&resume_flag);

    int last_number = 0;
    thrd_join(t,&last_number);
    PRINT_INT(last_number); 

    return 0;
}

解決方法四 鎖

#include <stdio.h>
#include <tinycthread.h>
#include <io_utils.h>

int count = 0;
mtx_t mutex;
int Counter(void*arg)
{
    for(int i = 0;i<100000;i++)
    {
        mtx_lock(&mutex);
        count++;
        mtx_unlock(&mutex);
        /*
         * int temp = count;
         * count=temp+1;
         * return temp;
         * */
    }
    return 0;
}

int main()
{
    mtx_init(&mutex,mtx_plain);
    thrd_t t1;
    thrd_t t2;

    thrd_create(&t1,Counter,NULL);
    thrd_create(&t2,Counter,NULL);

    thrd_join(t1,NULL);
    thrd_join(t2,NULL);
    PRINT_INT(count);
    mtx_destroy(&mutex);
    return 0;
}

解決方法五 執行緒儲存期

#include <stdio.h>
#include <tinycthread.h>
#include <io_utils.h>

_Thread_local int count = 0;//每個執行緒都有一個獨立的副本
int Counter(int* arg)
{
    for(int i = 0;i<100000;i++)
    {
        count+=*arg;
        /*
         * int temp = count;
         * count=temp+1;
         * return temp;
         * */
    }
    PRINT_INT(count);
    return 0;
}

int main()
{
    thrd_t t1;
    thrd_t t2;
    int arg_1 = 1;
    int arg_2 = 2;
    thrd_create(&t1,Counter,&arg_1);
    thrd_create(&t2,Counter,&arg_2);

    thrd_join(t1,NULL);
    thrd_join(t2,NULL);
    PRINT_INT(count);

    return 0;
    //count: 100000
    //count: 200000
    //count: 0
}

解決方法六 tss

#include <stdio.h>
#include <tinycthread.h>
#include <io_utils.h>

tss_t count_key;
void MyFree(void*ptr)
{
    PRINTLNF("free %#x",ptr);
    free(ptr);
}
int Counter(int* arg)
{
    int* count = malloc(sizeof(int));
    *count = 0;
    if(tss_set(count_key,count) == thrd_success) //如果繫結成功
    {
        for (int i = 0; i < 100000; i++) {
            *count += *arg;
            /*
             * int temp = count;
             * count=temp+1;
             * return temp;
             * */
        }
    }
    PRINT_INT(*count);
    PRINT_INT(*((int*)tss_get(count_key)));
    return 0;
}

int main()
{
    if(tss_create(&count_key,MyFree)==thrd_success)
    {
        thrd_t t1;
        thrd_t t2;

        int arg_1 = 1;
        int arg_2 = 2;

        thrd_create(&t1,Counter,&arg_1);
        thrd_create(&t2,Counter,&arg_2);
        //tss_delete(count_key); 如果線上程結束前刪除,則不會呼叫MyFree,需要自己手動釋放記憶體。
        thrd_join(t1,NULL);
        thrd_join(t2,NULL);

        puts("t_1,t_2 ends");
        tss_delete(count_key);
        PRINTLNF("count_key delete");
    }
    return 0;
}