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条都具备, ...
随机推荐
- New Questions
1. C++/Qt 实现一个信号槽 #include <functional> #include <iostream> #include <vector> clas ...
- 学习go语言编程之并发编程
并发基础 并发包含如下几种主流的实现模型: 多进程 多线程 基于回到的非阻塞/异步IO 协程 协程 与传统的系统级线程和进程相比,协程最大的优势在于"轻量级",可以轻松创建上百万个 ...
- 第127篇:异步函数(async和await)练习题(异步,消息队列)
好家伙,本篇为做题思考 书接上文 题目如下: 1.请给出下列代码的输出结果,并配合"消息队列"写出相关解释 async function foo() { console.lo ...
- 【Azure 事件中心】从Azure Event Hub中消费数据,如何查看当前消费客户端消费数据的Offset和SequenceNumber呢(消息偏移量和序列号)?
问题描述 当通过Azure Event Hub SDK消费Event Hub中的消息时,必须指定一个Storage Account(存储账号)用于保存 Checkpoint (检查点). 比如在C#代 ...
- 【Azure Developer】Windows中通过pslist命令查看到Java进程和线程信息,但为什么和代码中打印出来的进程号不一致呢?
通过PSLIST查看Windwos中的进程信息及线程信息 一:下载PSLIST小工具:https://docs.microsoft.com/en-us/sysinternals/downloads/p ...
- 【Azure 应用服务】Azure Function 中运行Powershell 脚本,定位 -DefaultProfile 引发的错误
问题描述 突然之间,使用PowerShell脚本 Get-AzVirtualNetwork 获取虚拟网络信息时,如果带上 -DefaultProfile $sub 参数,就出现 Azure cred ...
- .NET 全能 Cron 表达式解析库(支持 Cron 所有特性)
前言 今天大姚给大家分享一个.NET 全能 Cron 表达式解析类库,支持 Cron 所有特性:TimeCrontab. Cron表达式介绍 Cron表达式是一种用于配置定时任务的时间表达式.它由一系 ...
- YAML 语法简介与 C# 操作示例
〇.简介 YAML(Yet Another Markup Language)另一种标记语言. YAML 是一种较为人性化的数据序列化语言,可以配合目前大多数编程语言使用.YAML 的语法比较简洁直观, ...
- SSK:超级键盘模拟器,调用底层,可模拟所有按键
SSK - 吵架键盘模拟器 SuperSimulator of Keyboard 调用系统底层,能够模拟所有键盘操作! 本程序结合快Key(QuicKeys智能登录助手)一起使用,能够创造更多奇迹! ...
- FreeRTOS教程1 基础知识
1.准备材料 正点原子stm32f407探索者开发板V2.4 STM32CubeMX软件(Version 6.10.0) Keil µVision5 IDE(MDK-Arm) 野火DAP仿真器 2.学 ...