如何面对并发下的bug

embedded/2024/9/22 18:22:21/

整理总结自蒋炎岩老师的b站课程,https://jyywiki.cn/OS/2022/index.html

bug_1">并发bug与应对

  • 应对bug的方法

    • 在代码里边增加很多检查(加断言)

      • #include "thread.h"unsigned long balance = 100;void Alipay_withdraw(int amt) {if (balance >= amt) {usleep(1); // unexpected delaysbalance -= amt;}assert(balance <= 10000000);
        }void Talipay(int id) {Alipay_withdraw(100);
        }int main() {create(Talipay);create(Talipay);join();printf("balance = %lu\n", balance);
        }
        
    • 防御性编程:把程序需要满足的条件用 assert 表达出来。

      • 在这里插入图片描述

      • assert()

      • 在这里插入图片描述

  • 并发bug:死锁 (Deadlock)

    • A deadlock is a state in which each member of a group is waiting for another member, including itself, to take action.

    • ABBA-Deadlock

      • void swap(int i, int j) {spin_lock(&lock[i]);spin_lock(&lock[j]);arr[i] = NULL;arr[j] = arr[i];spin_unlock(&lock[j]);spin_unlock(&lock[i]);
        }
        
      • 上锁的顺序很重要……

        • swap 本身看起来没有问题,swap(1, 2); swap(2, 3), swap(3, 1) → 死锁
    • 避免死锁

      • 死锁产生的四个必要条件

        • 互斥:一个资源每次只能被一个进程使用
        • 请求与保持:一个进程请求资阻塞时,不释放已获得的资源
        • 不剥夺:进程已获得的资源不能强行剥夺
        • 循环等待:若干进程之间形成头尾相接的循环等待资源关系
      • AA-Deadlock

        • 在临界条件检测
        • spinlock-xv6.c中的各种防御性编程
          • if (holding(lk)) panic();
      • ABBA-Deadlock

        • 任意时刻系统中的锁都是有限的

        • 严格按照固定的顺序获得所有锁 (lock ordering; 消除 “循环等待”)

        • class LockOrdering:locks = [ '', '', '' ]def tryacquire(self, lk):self.locks[lk], seen = '🔒', self.locks[lk]return seen == ''def release(self, lk):self.locks[lk] = ''@threaddef t1(self):while True:while not self.tryacquire(0): passwhile not self.tryacquire(1): passwhile not self.tryacquire(2): passself.release(0), self.release(1), self.release(2)@threaddef t2(self):while True:while not self.tryacquire(1): passwhile not self.tryacquire(2): passself.release(1), self.release(2)
          
  • 并发bug:数据竞争 (Data Race)

    • 不同的线程同时访问同一段内存,且至少有一个是写。

    • 用互斥锁保护好共享数据,消灭一切数据竞争

    • 两种经典错误

      • // Case #1: 上错了锁
        void thread1() { spin_lock(&lk1); sum++; spin_unlock(&lk1); }
        void thread2() { spin_lock(&lk2); sum++; spin_unlock(&lk2); }
        
      • // Case #2: 忘记上锁
        void thread1() { spin_lock(&lk1); sum++; spin_unlock(&lk1); }
        void thread2() { sum++; }
        
  • 更多类型的并发 Bug

    • 忘记上锁——原子性违反 (Atomicity Violation, AV)

      • 我以为一段代码没啥事呢,但被人强势插入了

      • 在这里插入图片描述

      • 在这里插入图片描述

    • 忘记同步——顺序违反 (Order Violation, OV)

      • 在这里插入图片描述

      • 由于S4在S2之后执行,当S3执行时,造成了错误的结果

  • 应对并发 Bug 的方法

    • Lockdep: 运行时的死锁检查:lock/unlock

      • 为每一个锁确定唯一的 “allocation site”
        • lock-site.c
        • 为所分配了一个唯一性id,然后程序运行时存储上锁的顺序
        • assert: 同一个 allocation site 的锁存在全局唯一的上锁顺序
      • 检查方法:printf
        • 记录所有观察到的上锁顺序,例如[x,y,z]⇒xy,xz,yz
        • 检查是否存在 xyyx
    • ThreadSanitizer: 运行时的数据竞争检查:内存访问 + lock/unlock

      • 为所有事件建立 happens-before 关系图
        • Program-order + release-acquire
        • 对于发生在不同线程且至少有一个是写的 x,y 检查
        • 在这里插入图片描述
    • 动态分析工具:Sanitizers

    • 防御性编程:低配版 Lockdep

      • 给程序获取锁一个不可能超过的超时时间,当超过后打印日志,配合调试器和线程backtrace一秒锁定死锁

      • int spin_cnt = 0;
        while (xchg(&locked, 1)) {//自选100000000次,即打印日志if (spin_cnt++ > SPIN_LIMIT) {printf("Too many spin @ %s:%d\n", __FILE__, __LINE__);}
        }
        

http://www.ppmy.cn/embedded/34183.html

相关文章

使用 FFmpeg 从音视频中提取音频

有时候我们需要从视频文件中提取音频&#xff0c;并保存为一个单独的音频文件&#xff0c;我们可以借助 FFmpeg 来完成这个工作。 一、提取音频&#xff0c;保存为 mp3 文件: 要使用 FFmpeg 从音视频文件中提取音频&#xff0c;并将 ACC 编码的音频转换为 MP3 格式&#xff0…

基于 docker-compose 部署 LNMP 架构

目录 前言 1、任务要求 2、Nginx 2.1 建立工作目录并上传相关安装包 2.2 编写 Nginx Dockerfile 脚本 2.3 准备 nginx.conf 配置文件 3、Mysql 3.1 建立工作目录并上传相关安装包 3.2 编写 Mysql Dockerfile 脚本 3.3 编写 my.cnf 配置文件 4、PHP 4.1 建立工作目录…

PDF解析--PyMuPDF (python 文档解析提取)

1.介绍 PyMuPDF 和Fitz 是用于Python中处理PDF文件的相关模块。Fitz是P有MuPDF的字模块。提供一个简化和封装版本的P有MuPDF功能。 关系&#xff1a; PyMuPDF&#xff1a; 提供广泛的功能&#xff0c;用于操作PDF文档&#xff0c; 包括方便的高级函数与底层操作Fitz &#x…

java里的i/o流

在Java中&#xff0c;I/O&#xff08;输入/输出&#xff09;流是用于处理输入和输出操作的抽象概念。Java的I/O库提供了许多类和方法&#xff0c;用于从各种来源&#xff08;如文件、网络、内存等&#xff09;读取数据&#xff08;输入流&#xff09;&#xff0c;以及将数据写入…

安卓中常见的UI控件

TextView&#xff08;文本视图&#xff09;EditText&#xff08;编辑文本&#xff09;Button&#xff08;按钮&#xff09;ImageView&#xff08;图像视图&#xff09;ImageButton&#xff08;图像按钮&#xff09;CheckBox&#xff08;复选框&#xff09;RadioButton&#xff…

银行智能化数据安全分类分级实践分享

文章目录 前言一、数据安全智能分类分级平台建设背景二、数据安全分类分级建设思路和实践1、做标签– 数据安全标签体系2、打标签– 鹰眼智能打标平台 3.03、用标签– 全行统一“数据安全打标签结果”服务提供前言 随着国家对数据安全的高度重视,以及相关法律法规的出台,数据…

全方位了解 Meta Llama 3

本文将为您提供 Llama 3 的全面概览&#xff0c;从其架构、性能到未来的发展方向&#xff0c;让您一文了解这一革命性大语言模型的所有要点。 Meta Llama 发展历程 Llama 1 Llama 是由 Meta(FaceBook) AI 发布的一个开源项目&#xff0c;允许商用&#xff0c;影响力巨大。Lla…

数据存储-SQLite

一般使用到数据库存储&#xff0c;涉及到的数据量都较大&#xff0c;采用文件存储也能完成&#xff0c;但是文件操作复杂&#xff0c;效率低&#xff0c;大量结构化数据通常采用关系型数据库存储较为合适。Android中已经嵌入了轻量级的关系型数据库SQLite&#xff0c;直接按照数…