zoukankan      html  css  js  c++  java
  • Code Tips: 线程读写锁自旋导致的死循环

    发现问题   

        项目测试的时候,发现运行一段时间后会出现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 }

    运行结果,如下图

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

    分析原因

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

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

  • 相关阅读:
    Mysql性能优化
    PHP IF判断简写
    PHP与MYSQL事务处理
    js获取select标签选中的值
    oralce 的安装以及plsql的配置的html连接
    mysql 中启动服务的命令 、登录命令、退出命令 mysql 的常用命令
    oracle 中 某个字段的长度不够的sql 语句
    随机获得id的方法
    java中解析excel 批量插入数据库
    java 调用存储过程
  • 原文地址:https://www.cnblogs.com/tp1226/p/13923402.html
Copyright © 2011-2022 走看看