0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

使用静态分析查找并发错误

星星科技指导员 来源:嵌入式计算设计 作者:Paul Anderson 2022-06-19 10:00 次阅读

尽管几十年来小型化的进步已经为单处理器带来了巨大的性能提升,但这个时代似乎即将结束。使用单芯片实现显着额外性能的最佳选择是通过多个内核,但前提是软件可以编程以利用它们。

不幸的是,并发编程很困难。即使是只熟悉单线程编程的专家级程序员也常常无法理解并发程序容易受到诸如竞争条件、死锁和饥饿等全新类别的缺陷的影响。人类很难推理并发程序,并且编程语言本身的某些方面不适合并发。因此,专家们经常偶然发现这些危害。以下讨论描述了常见的并发缺陷,并解释了静态分析工具如何在不执行程序的情况下发现此类缺陷。

竞争条件的后果

当多个执行线程访问一个共享的数据并且其中至少一个线程在没有显式同步操作来分离访问的情况下更改该数据的值时,就会出现竞争条件。根据两个线程的交错,系统可能会处于不一致的状态。

种族条件特别阴险,因为它们可以无限期地潜伏而未被发现,并且只在极少数情况下出现,表现出难以诊断和重现的神秘症状。特别是,它们很可能通过对已部署软件的测试而存活下来。充其量,这意味着增加开发时间;在最坏的情况下,后果可能是毁灭性的。

2003 年东北大停电如此普遍的一个原因是计算机化能源管理系统中的竞争条件导致向运营商传达误导性信息。正如 Kevin Poulsen 在 2004 年的一篇文章 ( www.securityfocus.com/news/8412 ) 中指出的那样,“该漏洞有一个以毫秒为单位的机会窗口。” 在测试过程中出现此类问题的可能性微乎其微。在另一种情况下,iOS 4.0 到 4.1(现已修复)中的竞争条件意味着任何可以物理访问 iPhone 3G 或更高版本的人都可以在某些条件下绕过其密码锁定。

图 1 显示了一个简单竞争条件的示例。带有入口和出口传感器的制造装配线维护当前生产线上的项目的运行计数。每次项目进入行时,此计数都会增加,每次项目到达行尾并退出时,此计数就会减少。如果一个项目在另一个项目退出的同时进入该行,则计数应该递增然后递减(或反之亦然),以使净变化为零。但是,正常的递增和递减不是原子操作;它们由一系列单独的指令组成,这些指令首先从内存中加载值,然后在本地对其进行修改,最后将其存储回内存中。如果更新事务是在没有足够保护措施的多线程系统中处理的,由于传感器读取和写入共享数据:计数,因此可能会出现竞争条件。图 1 中的交错导致错误计数为 69。也有可能导致错误计数为 71 的交错,以及一些正确导致计数为 70 的交错。

图 1:竞争条件导致装配线上的项目计数不正确。

poYBAGKug2yAZX4YAAFML_Us9r8240.png

对于这个例子和一般的竞争条件错误,标准调试技术可能由于几个原因而无效。

很少发生意味着发现问题的机会减少。如果问题不经常出现,它可能永远不会在测试期间出现。这个问题是双重的。首先,两个线程中可能的指令交错数量可能很大,并且随着指令数量的增加而急剧增加。这种现象被称为组合爆炸。如果线程 A 执行M条指令,线程 B 执行N条指令,则两个线程的可能交错为:

等式 1

pYYBAGKug3OAajrHAAAvbcFv1Vc399.png

例如,给定两个普通线程,每个线程有 10 条指令,则指令有 184,756 种可能的交错。现实世界的软件庞大而复杂;测试每一个交织是根本不可能的。其次,即使测试人员可以识别出一些值得检查的交错,也很难设置测试用例来确保它们确实发生,因为线程调度可能是高度不确定的。

如果详尽的测试难以解决,那么开发人员可以做什么?一种非常有用的方法是静态分析。CodeSonar 等高级静态分析工具使用高度复杂的符号执行技术同时考虑许多可能的执行路径和交错。这些技术可以在不需要执行程序的情况下找到竞争条件和其他并发错误。

有几个因素使比赛状况诊断变得困难。首先,症状可能令人困惑。在图 1 示例中,运行计数通常是正确的,但有时太高,有时太低。其次,不习惯考虑多线程编程的特定缺陷的程序员可能会在可能出现竞争条件之前花费大量时间对代码感到困惑。高级静态分析工具在这方面特别有用。他们通过检查共享内存位置的访问模式来识别竞争条件;也就是说,他们关注的是种族本身,而不是它的症状。当识别出竞争条件时,高级静态分析工具将报告它以及支持信息,以帮助用户进行评估和调试。程序员的负担大大减轻。

更复杂,更多错误

竞争条件通常通过使用锁来保护共享资源来避免。但是,锁可能会引入性能瓶颈,可能会阻止程序充分利用多核的潜力,因此程序员在使用它们时必须小心谨慎。编写有效使用锁的代码可能很棘手,这种复杂性可能导致一组不同的问题,即死锁和饥饿。

在死锁中,两个或多个线程相互阻止,因为每个线程都持有另一个线程需要的锁。图 2 显示了如何使用用于保护两个共享变量的两个锁出现死锁。在此示例中,多条装配线共享当前正在装配的项目总数,第二个 bad_items 值记录有多少成品未通过质量控制。一个线程在 count 上获得锁,另一个在 bad_items 上获得锁。两个线程都无法获得它需要的第二个锁;因此既不能执行它的操作,也不能到达释放锁的地步。由于两个更新都无法完成,因此两个线程都完全卡住了。

图 2:在两个线程之间的死锁中,两个线程都无法前进。

poYBAGKug3yAXQzhAAIy7ley9hk593.png

静态分析工具可以通过标记不同线程可以以不同顺序获取相同锁的情况来识别存在死锁风险的软件,例如图 2 中所示的线程。消除所有此类情况足以确保系统不会陷入死锁。

饥饿是使用锁的多线程程序中发生的另一个问题。如果一个线程正在等待另一个线程当前持有的资源需要很长时间,它可能会饿死。例如,假设上述制造自动化系统包括一个定期审核线程,该线程检查所有进入和退出记录,以确保运行计数与进入的总项目数相匹配,而不是退出的总项目数。审计线程需要锁定计数和所有传感器,因此所有更新都必须等待审计完成。如果审核运行很长时间,更新可能会显着延迟。如果运行时间过长,下一次审计可能会设法获取所有锁并在未完成的线程取得任何进展之前开始运行。在最坏的情况下,部分或全部更新可能永远没有机会运行。

静态分析可以通过提出诸如“在持有锁时是否调用长时间运行的库函数?”之类的问题来提供重要的价值。CodeSonar 等工具还为用户提供了添加自己检查的机制。如果已知内部函数 f() 具有较长的运行时间,工程师可以添加自定义检查,每当持有一个或多个锁的线程调用 f() 时触发警告。

多线程为嵌入式开发人员必须考虑的潜在错误添加了全新的类别,使得查找各种错误变得更加困难。最新一代的静态分析工具可以帮助解决这两个问题。

审核编辑:郭婷

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 传感器
    +关注

    关注

    2526

    文章

    48080

    浏览量

    740004
  • 嵌入式
    +关注

    关注

    4981

    文章

    18278

    浏览量

    288376
  • 计算机
    +关注

    关注

    19

    文章

    6647

    浏览量

    84495
收藏 人收藏

    评论

    相关推荐

    ug内部错误,内存访问违例怎么解决

    问题,并提供一些预防这些问题的最佳实践方法。 一、内部错误原因和解决方法 1. 软件错误:软件错误是引起内部错误的最常见原因之一。这可能是由于编程
    的头像 发表于 12-27 16:27 3299次阅读

    xlookup查询结果错误值什么情况

    XLOOKUP函数是Excel中的一种查找函数,用于在指定范围中搜索某个值,并返回所查找的结果。当使用XLOOKUP函数时,可能会遇到错误值的情况。本文将详细介绍XLOOKUP函数的错误
    的头像 发表于 12-03 10:16 4166次阅读

    vlookup常见的12种错误

    VLOOKUP是Excel中非常常用的函数之一,它能够根据指定的值,在某一列范围内进行查找,并返回相应的值。虽然VLOOKUP是一个强大的函数,但是由于其复杂性和灵活性,常常容易出现一些错误。在本文
    的头像 发表于 12-01 11:19 1668次阅读

    c语言代码错误怎么找

    ,它们通常是由于C语言编写规则被打破所引起的。实际上,C编译器会提供非常详细的错误消息,告诉我们在哪个地方发生了错误。 当我们在编译过程中遇到语法错误时,我们需要仔细阅读编译器提供的错误
    的头像 发表于 11-24 10:05 1465次阅读

    服务器并发的概念

    自己调整系统的相关参数 并发的概念是什么?什么是并发? 对于服务器并发的概念,下面几点是错误的定义 ①服务器处理客户端请求的数量:没有时间、空间等限制,因此不能作为
    的头像 发表于 11-10 10:05 1370次阅读
    服务器<b class='flag-5'>并发</b>的概念

    Vulture 可在Python程序中查找未使用的代码

    Vulture 可以在Python程序中查找未使用的代码。这对于清理和查找大型项目(代码库)中的错误非常有用。 不过由于Python的动态特性,像 Vulture 这样的静态代码
    的头像 发表于 10-21 10:28 224次阅读

    CAN总线错误分析与解决 CAN节点发送错误不成功是什么原因

    CAN总线状态直接进入了BUS OFF状态,这意味着错误计数已经超限,查看CPU收发寄存器的收发错误计数显示发送错误计数TEC达到248, 接收错误计数为0。这很明显,数据压根没有发送
    发表于 08-01 14:37 3395次阅读
    CAN总线<b class='flag-5'>错误</b><b class='flag-5'>分析</b>与解决 CAN节点发送<b class='flag-5'>错误</b>不成功是什么原因

    什么是静态代码分析静态代码分析概述

    静态分析可帮助面临压力的开发团队。高质量的版本需要按时交付。需要满足编码和合规性标准。错误不是一种选择。 这就是开发团队使用静态分析工具/源
    的头像 发表于 07-19 12:09 922次阅读
    什么是<b class='flag-5'>静态</b>代码<b class='flag-5'>分析</b>?<b class='flag-5'>静态</b>代码<b class='flag-5'>分析</b>概述

    静态时序分析的相关概念

      本文主要介绍了静态时序分析 STA。
    的头像 发表于 07-04 14:40 590次阅读
    <b class='flag-5'>静态</b>时序<b class='flag-5'>分析</b>的相关概念

    最常见的PLC编程逻辑错误

    运行或运行到某个位置停止不前,才察觉出来有问题,再对PLC程序逐条逐句查找分析,或采取对程序逐条逐句执行,费时费工。
    的头像 发表于 06-16 12:53 737次阅读
    最常见的PLC编程逻辑<b class='flag-5'>错误</b>

    并发错误检测(3)#操作系统

    操作系统
    学习硬声知识
    发布于 :2023年06月01日 14:34:55

    并发错误检测(2)#操作系统

    操作系统
    学习硬声知识
    发布于 :2023年06月01日 14:34:11

    并发错误检测(1)#操作系统

    操作系统
    学习硬声知识
    发布于 :2023年06月01日 14:32:28

    FPGA静态时序分析简单解读

    任何学FPGA的人都跑不掉的一个问题就是进行静态时序分析静态时序分析的公式,老实说很晦涩,而且总能看到不同的版本,内容又不那么一致,为了彻底解决这个问题,我研究了一天,终于找到了一种
    的头像 发表于 05-29 10:24 372次阅读
    FPGA<b class='flag-5'>静态</b>时序<b class='flag-5'>分析</b>简单解读

    静态分析和动态分析的区别

    静态分析和动态分析是一种双管齐下的方法,可以在可靠性、错误检测、效率和安全性方面改进开发过程。为什么它们都很重要?它们又有什么区别呢?
    的头像 发表于 05-16 16:03 4001次阅读