Code Tips: 线程读写锁自旋导致的死循环

摘要:
在测试问题项目时,发现运行一段时间后,100%的CPU将出现。在检查了位置问题后,发现具有RT优先级的实时线程具有无限循环。因为配置了cpu的亲和属性,所以进程只在第一个内核上运行。此时,gdb无法连接。使用taskset在字段中修改进程的cpu亲和属性后,发现这个占cpu 100%的实时线程没有普通的循环,而是始终运行在pthread_ rwlock_ wrlock函数中,更奇怪的是,只要修改了cpu的亲和属性,就没有“循环”。

发现问题   

    项目测试的时候,发现运行一段时间后会出现cpu百分之百的情况。

    想着可能是哪里出现了死循环,于是打算用gdb跟一下,结果gdb居然无法attach到进程。

定位问题

    查了查去,原来有一个优先级为RT的实时线程出现了死循环,并且由于配置了CPU的亲和属性,使得进程只运行在第一个核上,此时gdb就无法attach了

    使用taskset现场修改进程的cpu亲和属性后,发现这个占cpu百分百的实时线程并没有出现一般的死循环,而是每次都在pthread_rwlock_wrlock这个函数中,

    而更诡异的是,只要修改了cpu亲和属性,就没有“死循环了”。

实验

    于是写了一段实验代码

 1 #define _GNU_SOURCE
 2 #include "stdio.h"
 3 #include "stdlib.h"
 4 #include "unistd.h"
 5 #include "pthread.h"
 6 #include <sched.h>
 7 
 8 pthread_rwlock_t rwlock;
 9 
10 void* task1(void *arg)
11 {
12     pthread_setname_np(pthread_self(), "task1");
13 
14     while(1)
15     {   
16         printf("
 task1 lock 
");
17         pthread_rwlock_wrlock(&rwlock);
18 
19         printf("
 task1 unlock 
");
20         pthread_rwlock_unlock(&rwlock);
21 
22         usleep(100);
23     }   
24 }
25 
26 void* task2(void *arg)
27 {
28     struct sched_param sparam;
29 
30     pthread_setname_np(pthread_self(), "task2");
31 
32     /* 设置为最高优先级的实时任务 */
33     sparam.sched_priority = sched_get_priority_max(SCHED_RR);
34     pthread_setschedparam(pthread_self(), SCHED_RR, &sparam);
35 
36     while(1)
37     {   
38         printf("
 task2 lock 
");
39         pthread_rwlock_wrlock(&rwlock);
40 
41         printf("
 task2 unlock 
");
42         pthread_rwlock_unlock(&rwlock);
43 
44         usleep(100);
45     }   
46 }
47 
48 int main(int argc, char *argv[])
49 {
50     pthread_t t1, t2, t3; 
51     cpu_set_t cpuset;
52 
53     /* 设置cpu亲和属性,将进程绑定在第一个核上 */
54     CPU_ZERO(&cpuset);
55     CPU_SET(0, &cpuset);
56     sched_setaffinity(0, sizeof(cpuset), &cpuset);
57 
58     pthread_rwlock_init(&rwlock, NULL);
59 
60     pthread_create(&t2, NULL, task1, NULL);
61     sleep(3);
62     pthread_create(&t3, NULL, task2, NULL);
63 
64     while (1)
65         sleep(10);
66 
67     return 0;
68 }

运行结果,如下图

Code Tips: 线程读写锁自旋导致的死循环第1张

真的出现了CPU百分百的情况!!!

分析原因

1. 读写锁的“拿锁”和“放锁”操作并不是一个完整的原子操作,而是有可能操作到一半被调度出去;

2. 此次实验结果显示,task1(非实时)在做unlock操作时,已经修改了一部分读写锁的属性,此时task2(实时)lock时,发现不需要再阻塞了,只需要自旋等待(死循环)task1将unlock操作做完;然而由于task2是实时任务,整个进程又只绑定到了第一个核上,task1无法得到调度,造成了task2的死循环。

免责声明:文章转载自《Code Tips: 线程读写锁自旋导致的死循环》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇SQL 中With as 的用法Android 利用Hierarchy Viewer工具学习别人的UI设计 狼人:下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Android学习——后台程序

Android学习——后台程序 在Android系统中我们一直在接触着前台界面程序,其实在一开始接触Android时就听说了,程序就有有界面和无界面之分。后台程序就是这类无界面的程序,它在后台执行,没有影响你的界面。比如短信监听程序,执行在后台,当有短信时才给你们提示,振动或声音;比如闹钟,设定好时间后,在定时通知你;再比如mp3播放器,选择好音乐后,在待...

pcre 使用

1、主页地址:http://www.pcre.org/下载pcre-7.8.tar.bz22、解压缩:tar xjpf pcre-7.8.tar.bz23、配置:cd pcre-7.8./configure --prefix=/usr/local/pcre-7.8 --libdir=/usr/local/lib/pcre --includedir=/usr...

NodeManager介绍

原文链接: http://blog.csdn.net/zhangzhebjut/article/details/37730013 参考文档: https://blog.csdn.net/u013384984/article/details/80738128          https://hortonworks.com/blog/how-to-plan...

mysql_【MySQL】常见的mysql 进程state

Analyzing 线程是对MyISAM 表的统计信息做分析(例如, ANALYZE TABLE )。 checking permissions 线程是检查服务器是否具有所需的权限来执行该语句。 Checking table 线程正在执行表检查操作。 cleaning up 线程处理一个命令,并正准备以释放内存和重置某些状态变量。 closing tabl...

收录 Uboot 详解

--------------------------------------------------------------------------------------------------------  我们知道,bootloader是系统上电后最初加载运行的代码。它提供了处理器上电复位后最开始需要执行的初始化代码。     在PC机上引导程序一般...

Sqlite多线程相关整理

Sqlite多线程相关整理 Sqlite With MultiThreads 什么是线程安全? 当多个线程访问某个方法时,不管你通过怎样的调用方式、或者说这些线程如何交替地执行,我们在主程序中不需要去做任何的同步,这个类的结果行为都是我们设想的正确行为,那么我们就可以说这个类是线程安全的。 一 来自官方FAQ https://www.sqlite.org/...