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;