多线程并发时原子操作的简单探究

26 篇文章 2 订阅
本文分享如何通过定义15s定时器和使用原子操作(_Atomic int)处理底层网络驱动中32位寄存器的流量统计翻转问题,确保数据准确无误地在web上展示。使用spin_lock_irqsave保护数据并发访问,避免死锁。
摘要由CSDN通过智能技术生成

之前写过一段代码,正好同事问起,深入学习分享一下。

背景

问题是这样,底层网络驱动相关的32bit寄存器记录了一个流量统计的数据,要在web上展示出来,之前的方案是直接通过ioctl读取走该值。但这时问题就出现了:在长时间的发流或大流量环境下,流量超过4G(2的32次方),寄存器统计就会发生翻转(从0开始统计)。
我的解决方案:
1、定义了一个15s的定时器,并定义了一个long long 类型数据,每次检查到数据翻转时,给该值累加4G的大小
2、加spinlock自旋锁turn_lock保护数据,由于定时器会访问并回写该值,web(用户态进程)会不定时的读取该值,可能会导致web拿到的并非最新数据,所以加锁保护。
PS:

spin_lock_irqsave(&turn_lock, flags);
.//保护区(临界区)
.
.
spin_unlock_irqrestore(&turn_lock, flags);

1、由于实际上不止一个数据,包括了收发、错误、丢弃等数据,所以使用锁来保护
2、web获取数据,需要通过中断(异常)陷入内核,最好使用spin_lock_irqsave函数来保护数据。原因:中断优先级高,可能会在定时器先获取到锁的情况下,同样获得锁,造成死锁;spin_lock_irqsave会1、保存中断状态2、关中断3、获取锁。之后spin_unlock_irqrestore恢复现场。(如果这里使用互斥锁,容易造成死锁)

原子操作

当下我们使用的PC应该都是多核,所以对于多个线程到底是并发还是并行,不是那么容易确定,因为这时操作系统分配的,但无论是并发还是并行,都会涉及到资源抢夺的问题。所以我们必须对需要保护的资源进行保护。

所谓原子操作,就是该操作绝不会在执行完毕前被任何其他任务或事件打断,也就说,它的最小的执行单位,不可能有比它更小的执行单位。

我们可以通过代码来看下,在多线程产生条件竞争时的情况。
通过声明两个线程,分别对变量进行递增操作:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <linux/types.h>

int b = 0;//声明全局变量b
void *fun1(){
	int i;
	for(i=0;i<1000000;i++){
		b++;
	}
	printf("%d\n",b);
}

int main(){
	int i;
	pthread_t thid[2];
	for(i =0;i<2;i++){
		pthread_create(&thid[i],NULL,(void*)fun1,NULL);
	}
	pthread_join(thid[0],NULL);
	pthread_join(thid[1],NULL);
	return	b;
}

运行下(注意编译时添加编译参数-lpthread):
在这里插入图片描述
代码声明两个线程,分别对全局变量b进行递增一百万次递增操作,按照正常,这里第二个线程运行结束,应该输出20,000,000但输出却小于二百万,这里原因就是产生了竞争。
过程如下:

**线程1**                                            **线程2**
获得b=5												——
增加b(5->6)										获得b=5
写回b(6)											增加b(5->6)
——													写回b(6)

致使同一个变量被同时访问,最后输出结果小于我们预期。

这时引入原子操作。
将上述代码中的b从新定义为:_Atomic int b = 0;
运行结果如下:
在这里插入图片描述
这时第二次打印结果为20,000,000,(前一打印是因为在第一个线程运行期间,第二个线程已经起来),毫无疑问这时正确的结果,因为两个原子操作绝不可能并发的访问同一个变量

另外,我们也可以通过汇编代码,看下原子量的操作,和普通变量有何不同。

参考
http://blog.chinaunix.net/uid-10747583-id-2920900.html

https://www.zhihu.com/search?type=content&q=%E5%8E%9F%E5%AD%90%E6%93%8D%E4%BD%9C

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值