weixin_42346462 2024-08-12 19:32 采纳率: 55.6%
浏览 11
已结题

c++动态多线程问题

想在c++中动态的生成多线程,代码如下:
类1:

.........................
ntp_client::ntp_client()
{
}

ntp_client::~ntp_client()
{ 
}

void ntp_client::run_ntp()
{
    while (true)
    {
        sleep(2);
    }
}

类2:动态生成线程类,代码如下:

class ntp_gather
{
private:
public:
    ntp_gather(); 
    ~ntp_gather();

    void ntp_gather_run();

    vector<string> m_vec_WhiteList;
    list<ntp_client *> m_arr_pNtpClient;
    list<thread *> m_arr_pNtpThread;
};
......
void ntp_gather::ntp_gather_run()
{
    m_vec_WhiteList.push_back("17.253.116.253");
    m_vec_WhiteList.push_back("162.159.200.1");

    ntp_client * pNtp_client = NULL;
    thread * pThread = NULL;
    for (vector<string>::iterator it = m_vec_WhiteList.begin(); it != m_vec_WhiteList.end(); ++it)
    {
        pNtp_client = new ntp_client();
        pNtp_client->m_TimeDeviation = appConfig.m_MaxTimeDeviation;
        pNtp_client->m_IP = *it;

        thread thread_ntp_gather(&ntp_client::run_ntp, &(*pNtp_client));
        pThread->detach();

        m_arr_pNtpClient.push_back(pNtp_client);
        m_arr_pNtpThread.push_back(pThread);
    }
}

以上程序编译能通过,在运行时总会内存错误(Segmentation fault (core dumped))。请问怎样修改,要求保留以上能动态创建线程的效果。

  • 写回答

10条回答 默认 最新

  • 才华横溢caozy 2024-08-12 19:40
    关注

    此答案是由GPT4和本人亲自作答,如有帮助,还请采纳!
    在 C++ 中进行多线程编程时,动态生成线程的过程中出现内存错误(如“Segmentation fault”)是比较常见的问题。这通常是由于访问了未初始化或已经释放的内存。为了改正代码中出现的内存错误,我们需要检查代码逻辑,确保线程和相关对象的正确创建、使用和释放。下面我将详细分析你的代码并给出修正方案。

    主要问题分析

    1. 未正确初始化 thread 指针:

      ntp_gather_run 函数中,每次创建新线程时,thread_ntp_gather 是一个局部变量,但你却将未初始化的指针 pThread 调用了 detach(),这将导致未定义行为。pThread 本身并没有指向有效的 thread 对象。

    2. thread 对象管理不当:

      你尝试动态管理线程,通过指针存储线程对象,但没有正确使用 new 来分配线程对象。直接使用局部 thread 对象的指针会导致访问非法内存。

    3. 资源管理:

      动态分配的对象(如 ntp_clientthread)没有在类的析构函数中释放,可能会导致内存泄漏。

    解决方案

    下面是解决上述问题的一个可能方案,修正了线程的创建和管理,同时确保资源的正确释放。

    #include <iostream>
    #include <vector>
    #include <list>
    #include <thread>
    #include <string>
    #include <unistd.h>
    
    using namespace std;
    
    class ntp_client
    {
    public:
        string m_IP;
        double m_TimeDeviation;
    
        ntp_client() {}
        ~ntp_client() {}
    
        void run_ntp()
        {
            while (true)
            {
                // 在这里实现实际的 NTP 操作逻辑
                sleep(2);
            }
        }
    };
    
    class ntp_gather
    {
    private:
        vector<string> m_vec_WhiteList;
        list<ntp_client *> m_arr_pNtpClient;
        list<thread> m_arr_pNtpThread; // 使用非指针列表来管理线程
    
    public:
        ntp_gather() {}
        ~ntp_gather()
        {
            // 在析构函数中释放动态分配的 ntp_client 对象
            for (auto client : m_arr_pNtpClient)
            {
                delete client;
            }
        }
    
        void ntp_gather_run()
        {
            m_vec_WhiteList.push_back("17.253.116.253");
            m_vec_WhiteList.push_back("162.159.200.1");
    
            for (auto &ip : m_vec_WhiteList)
            {
                ntp_client *pNtp_client = new ntp_client();
                pNtp_client->m_TimeDeviation = 5.0; // 假设的配置
                pNtp_client->m_IP = ip;
    
                // 使用 move 构造函数将线程对象存储到列表中
                m_arr_pNtpThread.emplace_back(&ntp_client::run_ntp, pNtp_client);
    
                m_arr_pNtpClient.push_back(pNtp_client);
            }
    
            // 分离所有线程
            for (auto &t : m_arr_pNtpThread)
            {
                t.detach();
            }
        }
    };
    
    int main()
    {
        ntp_gather gather;
        gather.ntp_gather_run();
    
        // 主线程做其他工作或保持运行
        while (true)
        {
            sleep(10);
        }
    
        return 0;
    }
    

    详细解释

    1. 线程管理改进:

      • m_arr_pNtpThread 改为 list<thread> 而不是 list<thread *>,以便直接在容器中存储线程对象。
      • 使用 emplace_back 直接构造并插入线程对象,避免了动态内存分配带来的复杂性和风险。
    2. 线程的生命周期:

      • 每个线程在创建后立即调用 detach,确保线程在后台运行,不会阻塞主线程的退出。
      • 如果需要等待所有线程完成,可以考虑使用 join 而不是 detach,但这需要管理线程的结束条件。
    3. 资源释放:

      • 在析构函数中遍历 m_arr_pNtpClient,释放动态创建的 ntp_client 对象,防止内存泄漏。

    总结

    通过以上方法,代码的线程管理更加清晰,避免了使用未初始化指针的问题。同时,资源管理也更加规范,确保动态分配的对象能被正确释放。在实际应用中,可能还需要处理更多的错误情况,比如线程创建失败或异常处理等。这是一个基础改进方案,可以作为进一步开发的基础。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(9条)

报告相同问题?

问题事件

  • 系统已结题 8月20日
  • 已采纳回答 8月12日
  • 创建了问题 8月12日

悬赏问题

  • ¥15 CCF-CSP 2023 第三题 解压缩(50%)
  • ¥30 comfyui openpose报错
  • ¥20 Wpf Datarid单元格闪烁效果的实现
  • ¥15 图像分割、图像边缘提取
  • ¥15 sqlserver执行存储过程报错
  • ¥100 nuxt、uniapp、ruoyi-vue 相关发布问题
  • ¥15 浮窗和全屏应用同时存在,全屏应用输入法无法弹出
  • ¥100 matlab2009 32位一直初始化
  • ¥15 Expected type 'str | PathLike[str]…… bytes' instead
  • ¥15 三极管电路求解,已知电阻电压和三级关放大倍数