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;
}
  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吃米饭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值