读书人

TThread Synchronize and quot;Out of Mem

发布时间: 2012-08-15 16:57:16 作者: rapoo

TThread Synchronize and "Out of Memory"
创建TThread时有如下提示:

//---------------------------------------

// Important: Methods and properties of objects in VCL can only be
// used in a method called using Synchronize, for example:
//
// Synchronize(&UpdateCaption);
//
// where UpdateCaption could look like:
//
// void __fastcall GetHistThread::UpdateCaption()
// {
// Form1->Caption = "Updated in a thread";
// }
//---------------------------------------

我在我的线程中使用了TStringList, TADOConnection, TADODataSet等是否属于VCL?是否要像上面提示的那样都放入Synchronize()中去做?

目前我碰到了非常古怪的问题,就是一直会报Out of Memory的错误,但实际上我机器还有很多很多的内存(分配到100M左右时就出现内存不足的错误,但其实我的机器总共有8G的内存)。

出错的TThread::Execute()函数如下:

C/C++ code
void __fastcall TGetHistThread::Execute(){    DWORD        dwTotalCount, dwCurrCount;    this->m_etErrorLevel = xelSystem;    m_strErrorMsg.sprintf("[历史数据缓冲线程]启动历史数据缓冲线程...");    Synchronize(&AddErrorMsg);    dwTotalCount = 0;    dwCurrCount = 0;    while( !Terminated )    {        if ( !ConnectDB() )        {            this->m_etErrorLevel = xelSystem;            m_strErrorMsg.sprintf("[历史数据缓冲线程]连接数据库失败,请检查配置.");            Synchronize(&AddErrorMsg);            MySleep(5000);            continue;        }        TStringList * pTables = Get5MTableNames();        TDateTime dtCurProdDt = m_dtStartDt;        TADODataSet * pDst = new TADODataSet(NULL);        pDst->Connection = m_pclAdoConn;        while(!Terminated)        {            dwCurrCount = 0;            m_strErrorMsg.sprintf("Producer: Waiting for mutex[%d]...", g_stGlobalVar.m_nProd);            Synchronize(&AddErrorMsg);            WaitForSingleObject(g_stGlobalVar.m_hMutex[g_stGlobalVar.m_nProd],INFINITE);            m_strErrorMsg.sprintf("Producer: Got Lock mutex[%d]. Continue.", g_stGlobalVar.m_nProd);            Synchronize(&AddErrorMsg);            TDateTime weekStart = dtCurProdDt;            TDateTime weekEnd = IncWeek(dtCurProdDt, 1);            m_strErrorMsg.sprintf("Producer: Buffering data from %s to %s",                weekStart.DateTimeString().t_str(), weekEnd.DateTimeString().t_str());            Synchronize(&AddErrorMsg);            // if reach end, set ret to false;            if(weekEnd >= m_dtEndDt) {                m_strErrorMsg.sprintf("Producer: Reach end datetime = %s", m_dtEndDt.DateTimeString());                Synchronize(&AddErrorMsg);                delete pTables;                pTables = NULL;                if(pDst->Active)                    pDst->Close();                delete pDst;                pDst = NULL;                Terminate();            }            // set str dates and times for sql search            DateTimeUtil sdt, edt;            sdt.SetStrDateTime(IncMinute(weekStart, -5));            edt.SetStrDateTime(weekEnd);            //std::list<AMQData> tempList;            for (int i = 0; i < pTables->Count; ++i)            {                if(i >= 3000)                    continue;                String strTableName = pTables->Strings[i];                if(pDst->Active)                    pDst->Close();                pDst->CommandType = cmdText;                pDst->CommandText = "\                    select * \                    from " + strTableName + " \                    where ((QuotaDate > " + sdt.strDate + ") or (QuotaDate = " + sdt.strDate + " and QuotaTime > " + sdt.strTime + ")) \                        and ((QuotaDate < " + edt.strDate + ") or (QuotaDate = " + edt.strDate + " and QuotaTime <= " + edt.strTime + ")) \                    ";                pDst->Open();                if (pDst->IsEmpty()) {                    pDst->Close();                    continue;                }                //tempList.clear();                pDst->First();                while(!pDst->Eof)                {                    AMQData data;                    data.m_QuotaInfo.m_iCjsl = pDst->FieldByName("Volumn")->AsInteger;                    data.m_QuotaInfo.m_fCjje = pDst->FieldByName("Amount")->AsFloat;                    strcpy(data.m_szHqrq, pDst->FieldByName("QuotaDate")->AsString.t_str());                    strcpy(data.m_QuotaInfo.m_szHqsj, pDst->FieldByName("QuotaTime")->AsString.t_str());                    strcpy(data.m_QuotaInfo.m_szZqdm, strTableName.SubString(6, 6).t_str());                    data.m_QuotaInfo.m_cJysdm = strTableName[5];                    if (data.m_QuotaInfo.m_iCjsl == 0) {                        data.m_QuotaInfo.m_fZjcj = pDst->FieldByName("Close")->AsFloat;                    } else {                        data.m_QuotaInfo.m_fZjcj = data.m_QuotaInfo.m_fCjje / data.m_QuotaInfo.m_iCjsl;                    }                    //data.SetTDateTime();                    g_stGlobalVar.tempList.push_back(data);                    pDst->Next();                    dwCurrCount++;                }                g_stGlobalVar.m_lstQuotaList[g_stGlobalVar.m_nProd].merge(g_stGlobalVar.tempList);            }            if(dwCurrCount > 0)            {                dwTotalCount += dwCurrCount;                //this->m_etErrorLevel = xelPrompt;                m_strErrorMsg.sprintf("[历史数据缓冲线程]缓冲成功(%d/%d).", dwCurrCount, dwTotalCount);                Synchronize(&AddErrorMsg);            }            // set dtCurProdDt to next week;            dtCurProdDt = weekEnd;            // set m_nProd to the other buffer (list)            int index = g_stGlobalVar.m_nProd;            g_stGlobalVar.m_nProd = !g_stGlobalVar.m_nProd;            // release producer buffer's mutex            ReleaseMutex(g_stGlobalVar.m_hMutex[index]);            m_strErrorMsg.sprintf("Producer: Releasing mutex[%d]", index);            Synchronize(&AddErrorMsg);            //MySleep(100);        }    }} 



我已经调试了一天了都没找到哪里出错了。望哪位大侠帮忙看一看。。。谢谢啦!

[解决办法]
这个Out of memory和你机器上的内存没关系,应该指的是你的进程虚拟内存空间的内存溢出。
[解决办法]
可能是死循环
[解决办法]
还有,就是消息阻塞!


[解决办法]
在提取数据后,少了一个pDst->Close()
[解决办法]
建议楼主把所有 ADO 操作, 都用 Synchronize 切换到主线程执行试试。 有时候,线程里面操作某些 VCL 组件时发生的错误, 切换到主线程就 OK 了。
[解决办法]
我在我的线程中使用了TStringList, TADOConnection, TADODataSet等是否属于VCL?是否要像上面提示的那样都放入Synchronize()中去做?
放到Synchronize()中去吧。

2可能数据库数据太多导致某些vcl内存溢出。
[解决办法]
单步跟一下,或打印一些调试日志
找到出错的地方,才好解决!
[解决办法]
仔细看了下:

// void __fastcall GetHistThread::UpdateCaption()
// {
// Form1->Caption = "Updated in a thread";
// }


肯定是消息阻塞; Form1->Caption = "Updated in a thread"; 会引起窗口重画.


解决办法:

1. 在Form1 里设一成员 String ThreadMessage;

2. 修改这个成员值为线程消息(所有的 Synchronize)

// Synchronize(&AddErrorMsg);
Form1->ThreadMessage = m_strErrorMsg;

3. 在 Form1 里使用 TTimer 来处理(Interval=256 就可以了)最新的 ThreadMessage.

[解决办法]
探讨

单步跟一下,或打印一些调试日志
找到出错的地方,才好解决!

[解决办法]
TADODataSet * pDst = new TADODataSet(NULL);

要及时 delete. 在下一次 new 之前,


也可以提到第一个 while( !Terminated ) 之前, 之后再 delete;

读书人网 >C++ Builder

热点推荐