前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >一个测试记录:利用【分段锁】来处理并发情况下的资源竞争问题

一个测试记录:利用【分段锁】来处理并发情况下的资源竞争问题

作者头像
IOT物联网小镇
发布于 2022-05-25 00:06:41
发布于 2022-05-25 00:06:41
40700
代码可运行
举报
文章被收录于专栏:IOT物联网小镇IOT物联网小镇
运行总次数:0
代码可运行

作 者:道哥,10+年嵌入式开发老兵,专注于:C/C++、嵌入式、Linux

目录

  • 问题描述
  • 测试代码
  • 测试结果
  • 测试代码简介

别人的经验,我们的阶梯!

在开发中经常遇到多个并发执行的线程,需要对同一个资源进行访问,也就是发生资源竞争。

在这种场景中,一般的做法就是加锁,通过锁机制对临界区进行保护,以达到资源独占的目的。

这篇文章主要描述的就是使用分段锁来解决这个问题,说起来很简单:就是把锁的粒度降低,以达到资源独占、最大程度避免竞争的目的。

问题描述

周末和朋友聊天说到最近的工作,他们有个项目,需要把之前的一个单片机程序,移植到x86平台。

由于历史的原因,代码中到处都充斥着全局变量,你懂得:在以前的单片机中充斥着大量的全局变量,方便、好用啊!

在代码中,尽量避免使用全局变量。坏处有:不方便模块化,函数不可重入,耦合性大。。。

由于大部分的单片机都只有一个CPU,是真正的串行操作。

也许你会说:会发生中断啊,这也是一种异步操作。

没错,但是可以在访问全局变量的地方把中断关掉,这样就不会避免了资源竞争的情况了。

但是,移植到x86平台之后,在多核的情况下,多个线程(任务)是真正的并发执行序列。

如果多个线程同时操作某一个全局变量,就一定存在竞争的情况。

针对这个问题,首先想到的方案就是:分配一般互斥锁,无论哪个线程想访问全局变量,首先获取到锁,然后才能操作全局变量,操作完成之后再释放锁。

但是,这个方案有一个很大的问题,就是:当并发线程很多的情况下,程序的执行效率太低。

他们最后的解决方案是分段加锁,也就是对全局变量按照数据索引进行分割,每一段数据分配一把锁。

至于每一段的数据长度是多少,这需要根据实际的业务场景进行调整,以达到最优的性能。

回来之后,我觉得这个想法非常巧妙。

这个机制看起来很简单,但是真的能解决大问题。

于是我就写了一段代码来测试一下:这种方案对程序的性能有多大的影响。

代码已经上传到网盘了,文末有具体的下载地址。

测试代码

在测试代码中,定义了一个全局变量:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
volatile int test_data[DATA_TOTAL_NUM];

数组的长度是10000(宏定义:DATA_TOTAL_NUM),然后创建100个线程来并发访问这个全局变量,每个线程访问100000次。

然后执行3个测试用例:

测试1:不使用锁

00个线程同时操作全局变量,访问的数据索引随机产生,最后统计每个线程的平均执行时间。

不使用锁的话,最后的结果(全局变量中的数据内容)肯定是错误的,这里仅仅是为了看一下时间消耗。

测试2:使用一把全局锁(大锁)

100个线程使用一把锁。

每个线程在操作全局变量之前,首先要获取到这把锁,然后才能操作全局变量,否则的话只能阻塞着等其它线程释放锁。

测试3:使用分段锁

根据全局变量的长度,分配多把锁。

每个线程在访问的时候,根据访问的数据索引,获取不同的锁,这样就降低了竞争的几率。

在这个测试场景中,全局变量test_data的长度是10000,每100个数据分配一把锁,那么一共需要100把锁。

比如,在某个时刻:

线程1想访问test_data[110],

线程2想访问test_data[120]

线程3想访问test_data[9900]

首先根据每个线程要访问的数据索引进行计算:这个索引对应的哪一把锁?

计算方式:访问索引 % 每把锁对应的数据长度

经过计算得知:线程1、线程2就会对第二把锁进行竞争;

而线程3就可以独自获取最后一把锁,这样的话线程3就避开了与线程1、线程2的竞争。

测试结果

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ ./a.out 
test1_naked:        average = 2876 ms 
test2_one_big_lock: average = 11233 ms 
test3_segment_lock: average = 3216 ms

从测试结果上看,分段加锁比使用一把全局锁,对于程序性能的提高确实很明显。

当然了,测试结果与不同的系统环境、业务场景有关,特别是线程的竞争程度、在临界区中的执行时间等。

测试代码简介

这里贴一下代码的结构,文末有完整的代码下载链接。

测试代码没有考虑跨边界的情况。

比如:某个线程需要访问190 ~ 210这些索引上的数据,这个区间正好跨越了200这个分界点。

第0把锁:0 ~ 99; 第1把锁:100 ~ 199; 第2把锁:200 ~ 299;

因此,访问190 ~ 210就需要同时获取到第1、2把锁。

在实际项目中需要考虑到这种跨边界的情况,通过计算开始和结束索引,把这些锁都获取到才可以。

当然了,为了防止发生死锁,需要按照顺序来获取。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#define THREAD_NUMBER           100         // 线程个数
#define LOOP_TIMES_EACH_THREAD  100000      // 每个线程中 for 循环的执行次数
#define DATA_TOTAL_NUM          10000       // 全局变量的长度
#define SEGMENT_LEN             100         // 多少个数据分配一把锁

volatile int test_data[DATA_TOTAL_NUM];     // 被竞争的全局变量

void main(void)
{
    test1_naked();
    test2_one_big_lock();
    test3_segment_lock();

    while (1)
        sleep(3);  // 主线程保持运行,也可以使用getchar();
}

// 测试1:子线程执行的函数
void *test1_naked_function(void *arg)
{
    struct timeval tm1, tm2;
    gettimeofday(&tm1, NULL);    
    for (unsigned int i = 0; i < LOOP_TIMES_EACH_THREAD; i++)
    {
        do_some_work();             // 模拟业务操作
        unsigned int pos = rand() % DATA_TOTAL_NUM; 
        test_data[pos] = i * i;     // 随机访问全局变量中的某个数据
    }
    gettimeofday(&tm2, NULL);   

    return (tm2 - tm1);
}

// 测试2:子线程执行的函数
void *test2_one_big_lock_function(void *arg)
{
    test2_one_big_lock_arg *data = (test2_one_big_lock_arg *)arg;
    struct timeval tm1, tm2;
    gettimeofday(&tm1, NULL);  
    for (unsigned int i = 0; i < LOOP_TIMES_EACH_THREAD; i++)
    {
        pthread_mutex_lock(&data->lock);  // 上锁

        do_some_work();             // 模拟业务操作
        unsigned int pos = rand() % DATA_TOTAL_NUM; 
        test_data[pos] = i * i;     // 随机访问全局变量中的某个数据

        pthread_mutex_unlock(&data->lock); // 解锁
    }
    gettimeofday(&tm2, NULL);    

    return (tm2 - tm1);
}

// 测试3:子线程执行的函数
void *test3_segment_lock_function(void *arg)
{
    test3_segment_lock_arg *data = (test3_segment_lock_arg *)arg;
    struct timeval tm1, tm2;
    gettimeofday(&tm1, NULL); 
    for (unsigned int i = 0; i < LOOP_TIMES_EACH_THREAD; i++)
    {
        unsigned int pos = rand() % DATA_TOTAL_NUM;      // 产生随机访问的索引
        unsigned int lock_index = pos / SEGMENT_LEN;     // 根据索引计算需要获取哪一把锁

        pthread_mutex_lock(data->lock + lock_index);     // 上锁

        do_some_work();             // 模拟业务操作
        test_data[pos] = i * i;     // 随机访问全局变量中的某个数据

        pthread_mutex_unlock(data->lock + lock_index);   // 解锁
    }
    gettimeofday(&tm2, NULL);     

    return (tm2 - tm1);
}

void test1_naked()
{
    创建 100 个线程,线程执行函数是 test1_naked_function()
    printf("test1_naked:        average = %ld ms \n", ms_total / THREAD_NUMBER);
}

void test2_one_big_lock()
{
    创建 100 个线程,线程执行函数是 test2_one_big_lock_function(),需要把锁作为参数传递给子线程。
    printf("test2_one_big_lock: average = %ld ms \n", ms_total / THREAD_NUMBER);
}

void test3_segment_lock()
{
    根据全局变量的长度,初始化很多把锁。
    创建 100 个线程,线程执行函数是 test2_one_big_lock_function(),需要把锁作为参数传递给子线程。

    printf("test3_segment_lock: average = %ld ms \n", ms_total / THREAD_NUMBER);
}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-04-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 IOT物联网小镇 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
架构师之路一-架构师入门指引
导读:本系列文章教你怎么样成为一名架构师,而本篇文章则带你先认识一下什么是架构师,架构师的工作是什么?
JAVA日知录
2020/03/12
3.3K0
如何成为合格的架构师
一直以来,在软件行业,对于什么是架构,都有很多的争论,每个人都有自己的理解。甚至于很多架构师一说架构,就开始谈论什么应用架构、硬件架构、数据架构等等。我曾经也到处寻找过架构的定义,请教过很多人,结果发现,没有大家都认可的定义。套用一句关于 big data 流行的笑话,放在架构上也适用:
leon公众号精选
2022/04/27
2810
如何成为合格的架构师
浅谈软件架构师的素质与职责
最近开始学习如何成为一名合格的架构师。首先参照别人的观点,在结合自己的实际经验,写出自己对如何成为一名架构师的理解,希望大家热心于与援手,能够指点一二. 沟通能力和自我表达 我认为沟通能力是基本中的基本,最为重要,最为普遍的素质。技术人员好像容易忽略,想成为架构师就不能忽略。因为架构师要做的第一件事就是与团队成员、项目经理、客户认同沟通,获得认同。我知道,这对于现在做技术,以后想转做架构的人也许很难.对本人也是如此。也许 你会注意到虽然你兢兢业业,老黄牛的做了很多事,但每次升迁的总是那些平时最活跃的人。抛除
张善友
2018/01/30
6740
【技术一号位指南🧭】谈谈我眼中的架构师
微软对架构师有一个分类:企业架构师EA(Enterprise Architect)、基础结构架构师IA(Infrastructure Architect)、特定技术架构TSA(Technology-Specific Architect)和解决方案架构师SA (Solution Architect)。这个分类是按照架构师专注的领域不同而划分。
小诚信驿站
2023/05/14
2.5K0
【技术一号位指南🧭】谈谈我眼中的架构师
系统架构设计师|关于系统架构设计师(下)
本篇为系统架构设计师的第二篇,主要说说何为系统架构设计师,他与系统架构之间的关系以及如何成为系统架构设计师,如有描述不清,还望指出。
六月暴雪飞梨花
2024/08/20
7780
系统架构设计师|关于系统架构设计师(下)
业务架构师、系统架构师、软件架构师:八卦三者的混淆与现象
相比于系统和软件的架构师,业务架构师更倾向于站在更高的战略层面,涉及商业分析、战略规划等。许多技术人员可能并未完全理解业务架构师的工作内容和重要性。
运维开发王义杰
2023/08/10
5120
业务架构师、系统架构师、软件架构师:八卦三者的混淆与现象
资深架构师十年总结:成为架构师,你必须具备这五点能力
作者 | Alan Tai 译者 | 冬雨 策划 | 闫园园 在过去的 20 年里,作为一名软件工程师和软件架构师,我与不同领域和不同学科的软件工程师聊过很多次。他们中有一些人是有着 8 到 10 年经验的高级工程师,有许多人还在职业生涯早期,有着 3 到 5 年的经验。其中一些人是我的同事。有些人是求职者。聊到最后,他们几乎都会问到同样一个问题: “我想成为一名解决方案架构师。了解更多架构相关内容的资源有哪些?“——很多软件工程师都会问的一个问题。 他们问错了问题。如果你读下去,就会知道为什么我
深度学习与Python
2023/03/29
5840
资深架构师十年总结:成为架构师,你必须具备这五点能力
架构师成长之路系列(一)
Architect,即架构一词可以溯源到希腊语ἀρχιτέκτων , 指的是建筑的规划,设计和建造过程和结果。现在也用于指系统的网络,软件,硬件的规划,设计和搭建过程。所以架构师就是从事架构设计的人。
数字悠客
2020/09/18
6040
干了5年程序员,该如何转行?5个新工作方向了解一下
写了5年代码,年龄已近30,头发尚存几缕,除了写代码其他并无所长,职业未来在何方?
大数据文摘
2019/10/29
1.4K0
干了5年程序员,该如何转行?5个新工作方向了解一下
业务架构师、系统架构师、软件架构师:职责、技能要求及对比分析
业务架构师、系统架构师和软件架构师在企业技术层面扮演着不同角色,各自有其独特的职责和技能要求。了解和明确这三者的不同,有助于组织有效地分配资源和角色,促进企业的技术和业务目标的实现。
运维开发王义杰
2023/08/10
3.5K0
业务架构师、系统架构师、软件架构师:职责、技能要求及对比分析
BAT资深架构师告诉你从程序员到架构师,你需要掌握什么能力?
架构师和开发者一样,也经常写代码,简单的说,开发者和架构师之间最大的区别就是技术领导力。
java架构师
2018/08/23
8460
Java程序员通往架构师的修炼之路
国内我们对架构师,项目经理,开发经理或者是技术总监这类职业定位普遍不都不清晰,很多的情况是“能者多劳”,一人身兼数职。达尔文的理论在我们的行业是绝对适用的,我从进入这个行业开始我就不甘于成为淘汰者,而我也由心地热爱着这个行业很年前我就立志要成为架构师(当年流行叫:系统分析员 )这目标进发。回首这10几年的磨练,我总结了一下一名合格的架构师应该具备哪一些方面的能力以及怎么才能得到这些能力 一、编码能力 架构师是一个职业,是一种经历了各种磨练与长年开发经验积累出来的。另外我一直认为:不会编码的架构师不是一个好的
Java架构
2018/07/06
3850
为什么你总成为不了架构师?
一,背景 今天接到一个哥们儿的电话,说,很郁闷,想和我聊聊。 我问,有啥郁闷的事情啊,说来听听。 他说,最近很郁闷,我本来今年的计划是成为一个架构师,但是,无论如何努力,都不知道为什么,感觉希望很渺茫
架构师小秘圈
2018/04/02
6410
为什么你总成为不了架构师?
设计图都不会画,还想做”架构师“?
什么是系统架构师? 系统架构师是一个既需要掌控整体又需要洞悉局部瓶颈并依据具体的业务场景给出解决方案的团队领导型人物。一个架构师得需要足够的想像力,能把各种目标需求进行不同维度的扩展,为目标客户提供更为全面的需求清单。 架构师在软件开发的整个过程中起着很重要的作用。 如何才能成为系统架构师? 首先必须具有丰富的软件设计与开发经验,这有助于理解并解释所进行的设计是如何映射到实现中去。 其次要具有领导能力与团队协作技能,软件架构师必须是一个得到承认的技术领导,能在关键时候对技术的选择作出及时、有效的决定。 第三
互扯程序
2018/03/26
26.9K2
设计图都不会画,还想做”架构师“?
成为java架构师需要具备那些技能?
大家好,又见面了,我是你们的朋友全栈君。架构师定义 百度百科,系统架构师是一个既需要掌控整体又需要洞悉局部瓶颈并依据具体的业务场景给出解决方案的团队领导型人物。 架构师工作职能 软件架构师在整个软件开发过程中都起着重要的作用,并随着开发进程的推进而其职责或关注点不断地变化,在需求阶段,软件架构师主要负责理解和管理非功能性系统需求,比如软件的可维护性、性能、复用性、可靠性、有效性和可测试性等等,此外,架构师还要经常审查客户及市场人员所提出的需求,确认开发团队所提出的设计;在需求越来越明确后,架构师的关注点开始转移到组织开发团队成员和开发过程定义上;在软件设计阶段,架构师负责对整个软件体系结构、关键构件、接口和开发政策的设计;在编码阶段,架构师则成为详细设计者和代码编写者的顾问,并且经常性地要举行一些技术研讨会、技术培训班等;随着软件开始测试、集成和交付,集成和测试支持将成为软件架构师的工作重点;在软件维护开始时,软件架构师就开始为下一版本的产品是否应该增加新的功能模块进行决策。 成为java架构师所需要具备那些技能? 所谓架构师,思考的是全局的东西,是如何组织你的系统,以达到业务要求,性能要求,具备可扩展性(scalability),可拓展性(extendability),前后兼容性等。可能涉及到的东西包括了从硬件到软件的方方面面,实在是一言难尽。 既然java架构师,首先你要是一个高级java攻狮城,熟练使用各种框架,并知道它们实现的原理。jvm虚拟机原理、调优,懂得jvm能让你写出性能更好的代码;池技术,什么对象池,连接池,线程池…:;java反射技术,写框架必备的技术,但是有严重的性能问题,替代方案java字节码技术;nio,没什么好说的,值得注意的是”直接内存”的特点,使用场景;java多线程同步异步;java各种集合对象的实现原理,了解这些可以让你在解决问题时选择合适的数据结构,高效的解决问题,比如hashmap的实现原理,好多五年以上经验的人都弄不清楚,还有为什扩容时有性能问题?不弄清楚这些原理,就写不出高效的代码,还会认为自己做的很对;总之一句话越基础的东西越重要,很多人认为自己会用它们写代码了,其实仅仅是知道如何调用api而已,离会用还差的远。 熟练使用各种数据结构和算法,数组、哈希、链表、排序树…,一句话要么是时间换空间要么是空间换时间,这里展开可以说一大堆,需要有一定的应用经验,用于解决各种性能或业务上的问题。 熟练使用linux操作系统,必备,没什么好说的。 熟悉tcp协议,创建连接三次握手和断开连接四次握手的整个过程,不了解的话,无法对高并发网络应用做优化;熟悉http协议,尤其是http头,我发现好多工作五年以上的都弄不清session和cookie的生命周期以及它们之间的关联。 系统集群、负载均衡、反向代理、动静分离,网站静态化。 分布式存储系统nfs,fastdfs,tfs,Hadoop了解他们的优缺点,适用场景。 分布式缓存技术memcached,redis,提高系统性能必备,一句话,把硬盘上的内容放到内存里来提速,顺便提个算法一致性hash。 工具nginx必备技能超级好用,高性能,基本不会挂掉的服务器,功能多多,解决各种问题。 数据库的设计能力,mysql必备,最基础的数据库工具,免费好用,对它基本的参数优化,慢查询日志分析,主从复制的配置,至少要成为半个mysqldba。其他nosql数据库如mongodb。 还有队列中间件。如消息推送,可以先把消息写入数据库,推送放队列服务器上,由推送服务器去队列获取处理,这样就可以将消息放数据库和队列里后直接给用户反馈,推送过程则由推送服务器和队列服务器完成,好处异步处理、缓解服务器压力,解藕系统。 想成为架构师不是懂了一大堆技术就可以了,这些是解决问题的基础、是工具,不懂这些怎么去提解决方案呢?这是成为架构师的必要条件。 架构师还要针对业务特点、系统的性能要求提出能解决问题成本最低的设计方案才合格,人家一个几百人用户的系统,访问量不大,数据量小,你给人家上集群、上分布式存储、上高端服务器,为了架构而架构,这是最扯淡的,架构师的作用就是第一满足业务需求,第二最低的硬件网络成本和技术维护成本。 架构师还要根据业务发展阶段,提前预见发展到下一个阶段系统架构的解决方案,并且设计当前架构时将架构的升级扩展考虑进去,做到易于升级;否则等系统瓶颈来了,出问题了再去出方案,或现有架构无法扩展直接扔掉重做,或扩展麻烦问题一大堆,这会对企业造成损失。
全栈程序员站长
2022/09/08
3690
师傅引进门,修行在个人--架构培训感言
成为一个优秀的架构师还有很长的路要走(软件架构案例分析和最佳实践培训收获) 2009-12-25到27日我们参加了某软件培训机构的的《软件架构案例分析和最佳实践》课程培训,开拓了眼界,收获很多,刘老师讲得不错,非常有实战经验,跟他学到了不少有关软件架构的知识,可惜的是3天的培训课程不可能完全掌握所有知识,师傅只是给我们打开了一扇门,指出了一个方向,成为一个优秀的架构师还有很长的路要走。 新视野 “软件架构”定义的决策因素 定义1:架构是一系列重要决策的集合 一直以来,学习架构,使用架构,关注点都仅限
用户1177503
2018/02/26
1K0
想要成为一个合格的架构师?看这篇文章就足够了......
在互联网圈,架构师这个名号的火热程度堪比产品经理,它在产品经理没火之前就已经风生水起。
Java高级架构
2018/10/22
6750
想要成为一个合格的架构师?看这篇文章就足够了......
架构师的成长之路
Architect,即架构一词可以溯源到希腊语ἀρχιτέκτων , 指的是建筑的规划,设计和建造过程和结果。现在也用于指系统的网络,软件,硬件的规划,设计和搭建过程。所以架构师就是从事架构设计的人。
BUG弄潮儿
2020/09/28
5920
架构师的成长之路
.NET 云原生架构师训练营(模块一 架构师与云原生)--学习笔记
Software architecture = {Elements, Forms, Rationale/Constraints}
郑子铭
2020/10/11
7400
.NET 云原生架构师训练营(模块一 架构师与云原生)--学习笔记
【说站】php架构师是做什么的
(1)架构师只对最终需求进行审查和确认,并提出需求不清和不完整的部分,他总是与需求分析师取得联系。架构师是技术专家,不是业务专家。
很酷的站长
2022/11/23
5310
【说站】php架构师是做什么的
推荐阅读
相关推荐
架构师之路一-架构师入门指引
更多 >
LV.5
这个人很懒,什么都没有留下~
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档