zoukankan      html  css  js  c++  java
  • gdb在线调试多线程程序

    之前面腾讯就被问过gdb能否调试正在运行的程序,今天写线程池demo时,恰好遇到程序"卡住了"。

    点击查看代码
    #include<pthread.h>
    #include<unistd.h>
    #include<stdio.h>
    #include<stdlib.h>
    #include<functional>
    #include<queue>
    #include<iostream>
    
    typedef std::function<void()> func;
    
    struct Job {
        int id;
        func run_func;
    };
    
    struct ThreadPool {
        pthread_t threads[8];  // 8个线程
        pthread_mutex_t m;   // 互斥锁
        pthread_cond_t cond;    // 条件变量
        std::queue<Job*>q;   // 任务队列
    
        ThreadPool() {
            for(int i = 0;i < 8;i++) {
                pthread_create(&threads[i], NULL, work_func, this);
            }
            pthread_mutex_init(&m, NULL);
            pthread_cond_init(&cond, NULL);
        }
    
        static void* work_func(void* args) {
            while(1) {
                Job* job = (static_cast<ThreadPool*>(args))->pop();
                job->run_func();
                // printf("thread %d\n", pthread_self());
                delete job;
            }
        }
    
        Job* pop() {
            // pthread_mutex_lock(&m);
            while(q.empty()) {  // 同时唤醒 或 虚假唤醒
                printf("wait before\n");
                pthread_cond_wait(&cond, &m);   // pthread_cond_wait会先解除之前的pthread_mutex_lock锁定的mtx,然后阻塞在等待对列里休眠,直到再次被唤醒(大多数情况下是等待的条件成立而被唤醒,唤醒后,该进程会先锁定先pthread_mutex_lock(&mtx);,再读取资源
                printf("wait after\n");
            }
            pthread_mutex_lock(&m);
            Job* job = q.front();   // 取出就绪的任务执行
            q.pop();
            pthread_mutex_unlock(&m);  
            return job;
        } 
    
        void add(Job* job) {
            pthread_mutex_lock(&m);
            q.push(job);   // 添加一个job到任务队列中
            pthread_cond_signal(&cond);  // 这个可以不改,当为了统一,也放到外面
            pthread_mutex_unlock(&m);
        }
    };
    
    int main() {
        ThreadPool pool;
        for(int i = 0;i < 10;i++) {
            Job* job = new Job();
            job->id = i;
            job->run_func = [i]() {
                printf("job %d\n", i);
            };
            pool.add(job);
        }
    
        for(int i = 0;i < 8;i++) {
            pthread_join(pool.threads[i], NULL);
        }
        printf("main end\n");
        return 0;
    } 
    

    运行上面的程序时有一定概率卡死,如图:
    预期是打印出Job 0...10

    gdb调试多线程

    1. 将进程附加到gdb调试器当中,查看是否创建了新线程:gdb attach 主线程ID

    看起来主线程是阻塞在__lll_lock_wait ()

    1. 查看栈信息 bt

    进一步发现,阻塞在main-> ThreadPool::add-> __GI___pthread_mutex_lock -> _L_lock_909-> __lll_lock_wait,总之,就是获取不到锁

    1. 查看线程:info threads

    可见,有8个线程阻塞在__lll_lock_wait,1个阻塞在pthread_cond_wait

    1. 切换线程:thread n (代表第几个线程)

    可见和主线程一样,都是获取不到锁,但是主线程是add中,线程池中的线程是pop中

    于是,我们知道大概可能的原因是:8号线程获得了锁但在等待条件变量,而其他线程获取不到锁而阻塞,并且不能给条件变量发送信号

    那互斥锁被谁占有了呢,只可能是8号线程了

    DESCRIPTION
    The pthread_cond_wait() function atomically blocks the current thread waiting on the condition variable specified by cond, and releases the mutex specified by mutex. The waiting thread unblocks only after another thread calls pthread_cond_signal(3), or pthread_cond_broadcast(3) with the same condition variable, and the current thread reacquires the lock on mutex.

    但是man文档说,pthread_cond_wait会先释放互斥锁的...迷

    总之,改成标准写法吧,把pthread_cond_wait放到mutex内,放在了gist 链接

    两个非常推荐的参考:
    线程的查看以及利用gdb调试多线程
    pthread_cond_wait()用法分析

  • 相关阅读:
    第14.15节 爬虫实战1:使用Python和selenium实现csdn博文点赞
    第14.14节 爬虫实战准备:csdn博文点赞过程http请求和响应信息分析
    第14.13节 BeautifulSoup的其他功能导览
    Mina源码阅读笔记(四)—Mina的连接IoConnector1
    H3C SecPath F100-C 防火墙配置说明
    基于数据仓库星形模式的广东省高速公路一张网资金结算情况分析系统
    祝贺自己的软件《万能数据库查询分析器》在中关村在线下载量超过10万次
    DB Query Analyzer has been downloaded more than 100,000 times
    图像处理程序框架—MFC相关知识点
    Graph Cuts学习笔记2014.5.16----1
  • 原文地址:https://www.cnblogs.com/lfri/p/15734588.html
Copyright © 2011-2022 走看看