如果 Main UI 线程正在休眠或不活动,如何检查工作线程内部
How to check inside the Worker thread if the Main UI Thread is sleeping or not active
我创建了一个 Visual Studio 2019 应用程序,带有 OutputPanes,其中一个用于查看来自 WorkerThread 的跟踪日志。
在 WorkerThread 中,如果发生了一些有用的事情,我会填充一个 CStringList mStrDebugList
,并通知 Main UI 和 PostMessage
现在阅读和显示。
//////////////////////////////////////////////////////////////////////////
// TRACE Debug messsages for this App wide
void TRACE_DEBUG(LPCTSTR pszstring)
{
TRACE(pszstring);
CTestApp* pApp = (CTestApp*)AfxGetApp();
if (pApp)
{
TAutoLock lock(res);
theApp.mStrDebugList.AddTail(pszstring);
}
这可行,但如果应用程序最小化或不在前台,数小时后 CStringList
包含太多元素(> 20k)并且 Main UI 无响应(~5 分钟)直到 UI.
中的所有元素都被读取并删除
void COutputWnd::FillInfoWindow()
{
TestApp* pApp = (CTestApp*)AfxGetApp();
if (pApp)
{
TAutoLock lock(res);
CString str;
while (!theApp.mStrDebugList.IsEmpty ())
{
str.Format(_T("%5d %s"),nCounter, theApp.mStrDebugList.GetHead ());
m_wndOutputDebug.AddString (str);
theApp.mStrDebugList.RemoveHead ();
}
// Scroll to the end of Listbox
int nCount = m_wndOutputDebug.GetCount();
m_wndOutputDebug.SetTopIndex(nCount-1);
}
}
我的问题是,如果 UI 未激活(休眠),我如何检查 WorkerThread 内部,以防止用太多元素填充 CStringList
?
我认为你的做法是错误的。如果 UI(主)线程处于“休眠”状态,您将做什么?阻止工作线程工作,即挂起它?它会不再收集数据吗?当 UI 再次出现在前台时会发生什么?工作线程将不得不收集所有数据,这些数据仍然需要一次性添加到调试 window,因此总响应时间会更长。
如果将数据添加到调试 window(我猜是列表框派生的 class)需要很长时间,没有真正的解决方案,无论如何都需要添加它们。只有一些优化:
- 在添加字符串之前调用
m_wndOutputDebug.SetRedraw(FALSE);
并在完成后调用 m_wndOutputDebug.SetRedraw(TRUE);
和 m_wndOutputDebug.Invalidate();
,延迟可能是由 UI 尝试绘制调试 window 添加每个项目后立即。
- 避免那些
GetHead()/RemoveHead()
浏览列表的调用(这是开销,因为它可能 rearrange/realloc 列表),而不是在完成后调用 RemoveAll()
,没有问题这是因为您锁定了操作。
旁注(与性能无关),为什么需要调用AfxGetApp()
?无论如何,您没有对它做任何事情 (pApp
)。并且您有可用的 theApp
单例(AfxGetApp()
应该只是 return theApp
的地址,不是吗?)。
我创建了一个 Visual Studio 2019 应用程序,带有 OutputPanes,其中一个用于查看来自 WorkerThread 的跟踪日志。
在 WorkerThread 中,如果发生了一些有用的事情,我会填充一个 CStringList mStrDebugList
,并通知 Main UI 和 PostMessage
现在阅读和显示。
//////////////////////////////////////////////////////////////////////////
// TRACE Debug messsages for this App wide
void TRACE_DEBUG(LPCTSTR pszstring)
{
TRACE(pszstring);
CTestApp* pApp = (CTestApp*)AfxGetApp();
if (pApp)
{
TAutoLock lock(res);
theApp.mStrDebugList.AddTail(pszstring);
}
这可行,但如果应用程序最小化或不在前台,数小时后 CStringList
包含太多元素(> 20k)并且 Main UI 无响应(~5 分钟)直到 UI.
void COutputWnd::FillInfoWindow()
{
TestApp* pApp = (CTestApp*)AfxGetApp();
if (pApp)
{
TAutoLock lock(res);
CString str;
while (!theApp.mStrDebugList.IsEmpty ())
{
str.Format(_T("%5d %s"),nCounter, theApp.mStrDebugList.GetHead ());
m_wndOutputDebug.AddString (str);
theApp.mStrDebugList.RemoveHead ();
}
// Scroll to the end of Listbox
int nCount = m_wndOutputDebug.GetCount();
m_wndOutputDebug.SetTopIndex(nCount-1);
}
}
我的问题是,如果 UI 未激活(休眠),我如何检查 WorkerThread 内部,以防止用太多元素填充 CStringList
?
我认为你的做法是错误的。如果 UI(主)线程处于“休眠”状态,您将做什么?阻止工作线程工作,即挂起它?它会不再收集数据吗?当 UI 再次出现在前台时会发生什么?工作线程将不得不收集所有数据,这些数据仍然需要一次性添加到调试 window,因此总响应时间会更长。
如果将数据添加到调试 window(我猜是列表框派生的 class)需要很长时间,没有真正的解决方案,无论如何都需要添加它们。只有一些优化:
- 在添加字符串之前调用
m_wndOutputDebug.SetRedraw(FALSE);
并在完成后调用m_wndOutputDebug.SetRedraw(TRUE);
和m_wndOutputDebug.Invalidate();
,延迟可能是由 UI 尝试绘制调试 window 添加每个项目后立即。 - 避免那些
GetHead()/RemoveHead()
浏览列表的调用(这是开销,因为它可能 rearrange/realloc 列表),而不是在完成后调用RemoveAll()
,没有问题这是因为您锁定了操作。
旁注(与性能无关),为什么需要调用AfxGetApp()
?无论如何,您没有对它做任何事情 (pApp
)。并且您有可用的 theApp
单例(AfxGetApp()
应该只是 return theApp
的地址,不是吗?)。