C++多线程内存泄漏问题

在主线程用AfxBeginThread开启子线程时,偶尔会报内存泄漏的错误(单线程没问题)
不是频繁报,10次有1~2次的样子,debug我也不知道怎么跟踪,怀疑是锁的问题加上
CCriticalSection cs; cs.Lock();cs.Unlock();后发现还是不行,求助!

 /*结构体*/
typedef struct _dlgTag
{
    int nIdx;
    CString strName;
} DLGTAG;



/*主线程代码*/
//初始化数组
m_Table.clear();
m_Table.swap(vector<vector<CString>>());
m_Table.resize(nLineCount);
for (int i = 0; i < nLineCount; i++)
{
    m_Table[i].resize(3);
}

//遍历
nThreadNum = 0;
nThreadAll = 30;
for (int i = 0; i < nLineCount; i++)
{
    //多线程工作
    if (nThreadNum < nThreadAll)
    {
        DLGTAG *dd = new DLGTAG();
        dd->nIdx = i;
        dd->strName = strLine;
        AfxBeginThread(LoopWorkThread, (LPVOID)dd);
        nThreadNum++;
        continue;
    }

    //轮巡线程池
    while (1)
    {
        int nNull = 0, nBegin = i - nThreadAll, nEnd = i;
        switch (nBegin)
        {
        case 0:
            nBegin++;
            nEnd++;
            break;
        default:
            break;
        }
        for (int j = nBegin; j < nEnd; j++)
        {
            if (m_Table[j][1].IsEmpty())
            {
                nNull++;
                Sleep(100);
            }
        }

        //已完成数
        if (nThreadAll - nNull > 0)
        {
            nThreadNum = nNull;
            i--;
            break;
        }
    }
}

//遍历结束检查线程是否全部执行完毕
while (1)
{
    int nNull = 0, nDone = 0;
    for (int i = 0; i < nLineCount; i++)
    {
        if (m_Table[i][1].IsEmpty())
        {
            nNull++;
            Sleep(100);
        }
    }
    nDone = nLineCount - nNull;
    if (nDone >= nLineCount)
    {
        break;
    }
}


/*子线程LoopWorkThread代码*/
CCriticalSection cs;
UINT LoopWorkThread(LPVOID pParam)
{
    DLGTAG* dlg = (DLGTAG*)pParam;
    CString strFlag = TestTest(dlg->nIdx, dlg->strName);
    if (strFlag == "成功")
    {
        cs.Lock();
        m_Table[dlg->nIdx][2] = 业务代码...
    }
    m_Table[dlg->nIdx][1] = strFlag;
    cs.Unlock();
    delete dlg;
    return 0;
}

5个回答

你检测下其它程序吧,VS2010 无error,无leak

 /*结构体*/
#include <vector>
using namespace std;
typedef struct _dlgTag
{
    int nIdx;
    CStringA strName;
    ~_dlgTag(){};
} DLGTAG;

struct SCPCCriticalSection
{
    CCriticalSection& cs;
    SCPCCriticalSection(CCriticalSection& cs_) :cs(cs_)
    {
        cs.Lock();
    }
    ~SCPCCriticalSection()
    {
        cs.Unlock();
    }
};
struct LineTable
{
private:
    vector<vector<CString>> m_Table;
    CCriticalSection cs;

    bool CheckTalbeSize(size_t f, size_t s) //  
    {
        return f < m_Table.size() && s < m_Table[f].size();
    }
public:
    void resize(size_t f, size_t s)
    {
        SCPCCriticalSection scp(cs);

        m_Table.resize(f);
        for (size_t n=0; n<f; n++)
            m_Table[n].resize(s);
    }

    BOOL set(size_t f, size_t s, const char* str)
    {
        SCPCCriticalSection scp(cs);

        ASSERT(CheckTalbeSize(f, s));
        if (f >= m_Table.size() || s >= m_Table[f].size())
            return false;
        m_Table[f][s] = str;
        return true;
    }

    BOOL IsEmpty(size_t f, size_t s)
    {
        SCPCCriticalSection scp(cs);

        ASSERT(CheckTalbeSize(f, s));
        if (f >= m_Table.size() || s >= m_Table[f].size())
            return true;
        return m_Table[f][s].IsEmpty();
    }
};

LineTable g_LineTable;

//
const char*  TestTest(int nIdx, const char* strName)
{
    OutputDebugStringA(strName);
    if (nIdx&1)
        return "成功";
    else 
        return "失败";
}

/*子线程LoopWorkThread代码*/
UINT LoopWorkThread(LPVOID pParam)
{
    DLGTAG* dlg = (DLGTAG*)pParam;
    CStringA strFlag = TestTest(dlg->nIdx, dlg->strName);
    if (strFlag == "成功")
    {
        //cs.Lock();
        //m_Table[dlg->nIdx][2] = 业务代码...
        BOOL b =g_LineTable.set(dlg->nIdx, 2, "业务代码...");
        ASSERT(b);
    }
 //   m_Table[dlg->nIdx][1] = strFlag;
   // cs.Unlock();
    BOOL b =g_LineTable.set(dlg->nIdx, 1, strFlag);
    ASSERT(b);

    delete dlg;
    return 0;
}


void CListCtrlEx测试Dlg::OnBnClickedButton1()
{
    // TODO: 在此添加控件通知处理程序代码

    /*主线程代码*/
    //初始化数组
//  m_Table.clear();
//  m_Table.swap(vector<vector<CString>>());
//  m_Table.resize(nLineCount);
//  for (int i = 0; i < nLineCount; i++)
//  {
//      m_Table[i].resize(3);
//  }

    //遍历
    int nThreadNum = 0;
    int nThreadAll = 100;
    const int nLineCount =150;
    g_LineTable.resize(nLineCount, 3);
    const char* strLine = "strLine";
    for (int i = 0; i < nLineCount; i++)
    {
        //多线程工作
        if (nThreadNum < nThreadAll)
        {
            DLGTAG *dd = new DLGTAG();
            dd->nIdx = i;
            dd->strName = strLine;
            AfxBeginThread(LoopWorkThread, (LPVOID)dd);
            nThreadNum++;
            continue;
        }

        //轮巡线程池
        while (1)
        {
            int nNull = 0, nBegin = i - nThreadAll, nEnd = i;
            switch (nBegin)
            {
            case 0:
                nBegin++;
                nEnd++;
                break;
            default:
                break;
            }
            for (int j = nBegin; j < nEnd; j++)
            {
                //if (m_Table[j][1].IsEmpty())
                if (g_LineTable.IsEmpty(j, 1))
                {
                    nNull++;
                    Sleep(100);
                }
            }

            //已完成数
            if (nThreadAll - nNull > 0)
            {
                nThreadNum = nNull;
                i--;
                break;
            }
        }
    }

    //遍历结束检查线程是否全部执行完毕
    while (1)
    {
        int nNull = 0, nDone = 0;
        for (int i = 0; i < nLineCount; i++)
        {
            //if (m_Table[i][1].IsEmpty())
            if (g_LineTable.IsEmpty(i, 1))
            {
                nNull++;
                Sleep(100);
            }
        }
        nDone = nLineCount - nNull;
        if (nDone >= nLineCount)
        {
            break;
        }
    }


}
useready
useready 好的,谢谢
3 年多之前 回复

delete[] pParam;
错了,应当
delete dlg ;
因为上面上不会调用析构函数

useready
useready 你好,谢谢你的回答,刚试了下修改这里后还是会报 内存不能为“read”的错误。
3 年多之前 回复
for (int i = 0; i < nLineCount; i++)
//...
 int nNull = 0, nBegin = i - nThreadAll, nEnd = i;   // nBegin <0; 什么意思、 nBegin=0吧
 for (int j = nBegin; j < nEnd; j++)
        {
            if (m_Table[j][1].IsEmpty())  //  不然 m_Table[j];j小于0
            {
                nNull++;
                Sleep(100);
            }
        }

useready
useready 你好,这里nBegin应该不会小于0的啊,在线程那里加了continue,只有i大于线程数时才会执行到这里
3 年多之前 回复

把全局变量封装一下,原程序lock, unlock对全局变量并未完全用到
ps: 手写,未检测


//vector<vector<CString>> m_Table;

struct SCPCCriticalSection
{
    CCriticalSection& cs;
    SCPCCriticalSection(CCriticalSection& cs_) :cs(cs_)
    {
        cs.Lock();
    }
    ~SCPCCriticalSection()
    {
        cs.Unlock();
    }
};
struct LineTable
{
    vector<vector<CString>> m_Table;
    CCriticalSection cs;

    void resize(int f, int s)
    {
        SCPCCriticalSection scp(cs);

        m_Table.resize(f);
        for (int n=0; n<f; n++)
            m_Table[n].resize(s);
    }

    BOOL set(int f, int s, const char* str)
    {
        SCPCCriticalSection scp(cs);

        if (f >= m_Table.size() || s >= m_Table[f].size())
            return false;
        m_Table[f][s] = str;
        return true;
    }

    BOOL IsEmpty(int f, int s)
    {
        SCPCCriticalSection scp(cs);

        if (f >= m_Table.size() || s >= m_Table[f].size())
            return true;
        return m_Table[f][s].IsEmpty();
    }
};

//...
   CString strFlag = TestTest(dlg->nIdx, dlg->strName);
    if (strFlag == "成功")
    {
        //cs.Lock();
        //m_Table[dlg->nIdx][2] = 业务代码...
        g_LineTable.set(dlg->nIdx, 2, 业务代码...);
    }
    //m_Table[dlg->nIdx][1] = strFlag;
   // cs.Unlock();
    g_LineTable.set(dlg->nIdx, 2, strFlag);

    //.....
    //if (m_Table[j][1].IsEmpty())
                if (g_LineTable.IsEmpty(j, 1))
        //.....
        //if (m_Table[i][1].IsEmpty())
            if (g_LineTable.IsEmpty(i, 1))
useready
useready 你好,用这种方式测试了下偶尔还是会报内存不能为“read”的错误(0xf7d7d9b2). 实在头疼,不知道是不是网上说的CString不能用作结构体?
3 年多之前 回复
useready
useready 太谢谢你了,节后上班试一下
3 年多之前 回复

你好,用这种方式测试了下偶尔还是会报内存不能为“read”的错误(0xf7d7d9b2). 实在头疼,不知道是不是网上说的CString不能用作结构体?

Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问