并发缺陷分类及详述

在已开发的成熟的web服务器以及数据库管理系统 例如Mysql Apache中,通过统计这些应用历次进行并发缺陷修复时可以看到,大部分并发缺陷均为非死锁缺陷,有大概四分之一的缺陷为死锁缺陷

非死锁缺陷:违反原子性(atomicity violation)缺陷和错误顺序(order violation)缺陷

违反原子性:

  1. 1Thread1::
  2. 2if(thd->proc_info){
  3. 3...
  4. 4 fputs(thd->proc_info,...);
  5. 5...
  6. 6}
  7. 7
  8. 8Thread2::
  9. 9 thd->proc_info = NULL;

这个典型例子说明了在进程1和进程2并发执行的过程中,调用空指针pro_info 导致程序崩溃。

根据Lu等人,更正式的违反原子性的定义是:“违反了多次内存访问中预期的可串行性(即代码段本意是原子的,但在执行中并没有强制实现原子性)”。

修复的方法:(加锁)

  1. 1pthread_mutex_t proc_info_lock = PTHREAD_MUTEX_INITIALIZER;
  2. 2
  3. 3Thread1::
  4. 4 pthread_mutex_lock(&proc_info_lock);
  5. 5if(thd->proc_info){
  6. 6...
  7. 7 fputs(thd->proc_info,...);
  8. 8...
  9. 9}
  10. 10 pthread_mutex_unlock(&proc_info_lock);
  11. 11
  12. 12Thread2::
  13. 13 pthread_mutex_lock(&proc_info_lock);
  14. 14 thd->proc_info = NULL;
  15. 15 pthread_mutex_unlock(&proc_info_lock);

违反顺序缺陷:

  1. Thread1::
  2. void init(){
  3. ...
  4.  mThread = PR_CreateThread(mMain,...);
  5. ...
  6. }
  7. Thread2::
  8. void mMain(...){
  9. ...
  10.  mState = mThread->State;
  11. ...
  12. }

这个例子说明了当进程1和2并发执行时,由于在调用MThread之前可能还未初始化,导致程序出现问题。违反顺序更正式的定义是:“两个内存访问的预期顺序被打破了(即A应该在B之前执行,但是实际运行中却不是这个顺序)”

我们通过强制顺序来修复这种缺陷。

  1. pthread_mutex_t mtLock = PTHREAD_MUTEX_INITIALIZER;
  2. pthread_cond_t mtCond = PTHREAD_COND_INITIALIZER;
  3. int mtInit =0;
  4. Thread1::
  5. void init(){
  6. ...
  7.  mThread = PR_CreateThread(mMain,...);
  8. // signal that the thread has been created...
  9.  pthread_mutex_lock(&mtLock);
  10.  mtInit =1;
  11.  pthread_cond_signal(&mtCond);
  12.  pthread_mutex_unlock(&mtLock);
  13. ...
  14. }
  15. Thread2::
  16. void mMain(...){
  17. ...
  18. // wait for the thread to be initialized...
  19.  pthread_mutex_lock(&mtLock);
  20. while(mtInit ==0)
  21.  pthread_cond_wait(&mtCond,&mtLock);
  22.  pthread_mutex_unlock(&mtLock);
  23.  mState = mThread->State;
  24. ...
  25. }

非死锁缺陷:小结

大部分(97%)的非死锁问题是违反原子性和违反顺序这两种。因此,程序员仔细研究这些错误模式,应该能够更好地避免它们。此外,随着更自动化的代码检查工具的发展,它们也应该关注这两种错误,因为开发中发现的非死锁问题大部分都是这两种。

然而,并不是所有的缺陷都像我们举的例子一样,这么容易修复。有些问题需要对应用程序的更深的了解,以及大量代码及数据结构的调整。

死锁缺陷

除了上面提到的并发缺陷,死锁(deadlock)是一种在许多复杂并发系统中出现的经典问题。例如,当线程1持有锁L1,正在等待另外一个锁L2,而线程2持有锁L2,却在等待锁L1释放时,死锁就产生了。以下的代码片段就可能出现这种死锁:

  1. Thread1:Thread2:
  2. lock(L1);lock(L2);
  3. lock(L2);lock(L1);

数据竞争(data race)是指在非线程安全的情况下,多线程对同一个地址空间进行写操作。一般来说,我们都会通过线程同步方法来保证数据的安全,比如采用互斥量或者读写锁。但是由于某些笔误或者设计的缺陷,还是存在data race的可能性的。

若线程的类型状态发生改变,且没有与另外线程的其他操作同步,则会造成对象执行其类型状态中不允许的操作,从而产生并发类型状态缺陷。

使用模型检测来进行并发缺陷检测的流程:

模型检测是一种验证有限状态系统时序逻辑属性的形式化方法。首先将软件构造为状态机等抽象模型,然后使用模态/时序逻辑公式等形式化的表达式来描述安全属性,最终对模型进行遍历以验证软件是否满足安全属性,从而判断是否存在缺陷。Verisoft[33]是基于程序执行信息提取的模型检测工具,通过调度程序执行,利用程序执行信息(堆、栈和寄存器等)构造状态转换图(Kripke图),然后进行属性验证。此后,Verisoft,JPF[34]和SPIN[35]模型检测工具得到了广泛应用。模型检测可以检测到并发缺陷中:死锁,数据竞争,顺序性违背和原子性违背四种缺陷。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值