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;
}
C语言线程安全问题的更多相关文章
- DP #1 Singleton Pattern线程安全问题
单例模式确保一个类只有一个实例,自行提供这个实例并向整个系统提供这个实例. 其中涉及到最主要的问题就是在多线程并发时线程安全问题. 单例模式的实现也有一个循序渐进的过程:1.最基本要求:每次从getI ...
- 【C#复习总结】探究各类数据结构(Array、List、Queue、Stack)及线程安全问题和yeild关键字
前言 先普及一下线程安全和类型安全 线程安全: 如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码.如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的 ...
- Java并发编程基础-线程安全问题及JMM(volatile)
什么情况下应该使用多线程 : 线程出现的目的是什么?解决进程中多任务的实时性问题?其实简单来说,也就是解决“阻塞”的问题,阻塞的意思就是程序运行到某个函数或过程后等待某些事件发生而暂时停止 CPU 占 ...
- ASP.NET MVC深入浅出系列(持续更新) ORM系列之Entity FrameWork详解(持续更新) 第十六节:语法总结(3)(C#6.0和C#7.0新语法) 第三节:深度剖析各类数据结构(Array、List、Queue、Stack)及线程安全问题和yeild关键字 各种通讯连接方式 设计模式篇 第十二节: 总结Quartz.Net几种部署模式(IIS、Exe、服务部署【借
ASP.NET MVC深入浅出系列(持续更新) 一. ASP.NET体系 从事.Net开发以来,最先接触的Web开发框架是Asp.Net WebForm,该框架高度封装,为了隐藏Http的无状态模 ...
- 被我们忽略的HttpSession线程安全问题
1. 背景 最近在读<Java concurrency in practice>(Java并发实战),其中1.4节提到了Java web的线程安全问题时有如下一段话: Servlets a ...
- Java多线程--线程安全问题的相关研究
在刚刚学线程的时候我们经常会碰到这么一个问题:模拟火车站售票窗口售票.代码如下: package cn.blogs.com.isole; /* 模拟火车站售票窗口售票,假设有50张余票 */ publ ...
- struts2学习笔记--线程安全问题小结
在说struts2的线程安全之前,先说一下,什么是线程安全?这是一个网友讲的, 如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码.如果每次运行结果和单线程运行的结果是一样 ...
- iOS中的线程安全问题
为了保证线程安全,不会因为多个线程访问造成资源抢夺,出现的运行结果的偏差问题,我们需要使用到线程同步技术,最常用的就是 @synchronized互斥锁(同步锁).NSLock.dispatch_se ...
- java 22 - 13 多线程之解决线程安全问题的实现方式2
上一章说了,解决线程安全问题的实现方式1是使用同步代码块 同时也知道了,同步代码块的锁对象是任意对象:(Object obj ; Demo d;)这些都行 那么,现在来说解决线程安全问题的实现方式2 ...
- java 22 - 12 多线程之解决线程安全问题的实现方式1
从上一章知道了多线程存在着线程安全问题,那么,如何解决线程安全问题呢? 导致出现问题的原因: A:是否是多线程环境 B:是否有共享数据 C:是否有多条语句操作共享数据 上一章的程序,上面那3条都具备, ...
随机推荐
- win32-StretchDIBits - PrintDlg
使用StretchDIBits将位图数据传输到printer的dc中 #include <Windows.h> #include <algorithm> int main() ...
- 都说了别用BeanUtils.copyProperties,这不翻车了吧
分享是最有效的学习方式. 博客:https://blog.ktdaddy.com/ 故事 新年新气象,小猫也是踏上了新年新征程,自从小猫按照老猫给的建议[系统梳理大法]完完整整地梳理完毕系统之后,小猫 ...
- PMP考试之【PMBOK(第六版)49个过程及ITTO】
- 记一次酣畅淋漓的 K8s Ingress 排错过程(302,404,503,...)
故事开始 第 1 关:[流量重定向到 /] 第 2 关:[应用返回 302,重定向到 /,引入 503 错误] 第 3 关:[静态资源访问遇到 503 问题] 第 4 关:[静态资源访问遇到 403 ...
- 【Azure Cloud Service】Cloud Service(Classic) 迁移失败,找不到解决方案怎么办?
问题描述 很老很老的云服务,在迁移到 Cloud Service(Extended Support)[云服务外延支持] 时,迁移的验证步骤不通过,因为资源中没有包含虚拟网络(Virtual Netwo ...
- 【Azure Notification Hub】创建Notification Hub失败,提示 unrecognized arguments: --sku Free
问题描述 用Azure CLI命令创建 Notification Hub,报错不识别的参数 --Free SKU 问题解答 经测试发现,在创建Notification Hub前,需要创建 Notifi ...
- map 简单梳理【GO 基础】
〇.map 简介 map 是一种无序的基于 key-value 的数据结构,Go 语言中的 map 是引用类型,必须初始化才能使用. 其中键可以是任何类型,但值必须是可比较的类型(如整数.字符串.布尔 ...
- viewui tree 自定义化(源码copy出来改动)#添加 获取selected 解决方案
需求: 对树有title的点击效果,右侧有说明文字 和 按钮能点击,不能右键,系统用的壳已经有右键了. 出现的问题: viewui的tree有两年没更新了,对ui这块,是采取的render自定义,但是 ...
- HUAWEI WATCH GT3手表芯片传感器简析
一 这里梳理一下华为手表GT3所使用的芯片 芯片A: BES2500L 恒玄BES2500L智能手表SoC,集存储.音频.连接为一体,集成BT5.2双模蓝牙,可支持BLE数据传输.蓝牙通话和音乐播放功 ...
- 05_QT_Mac开发环境搭建
在不同的Mac环境下,实践出来的效果可能跟本教程会有所差异.我的Mac环境是:Intel CPU.macOS Moterey(12.4). FFmpeg 安装 在Mac环境中,直接使用Homebrew ...