C++ 避免";(没有回应)“;一次处理大量数据时在windows中添加标签
我偶尔需要从网络上处理一个包中的大量数据,这需要足够长的时间,当用户尝试与应用程序交互时,windows会在窗口标题中添加“(无响应)”字符串。我知道这是因为处理是在一个调用中完成的,以处理一条消息(在堆栈的某个位置),因此阻塞了消息泵。我也知道处理这个问题的理想方法是在一个单独的线程中异步处理数据,这样泵就可以继续运行,但是这是一个从上到下的单线程的大型桌面应用程序,在我们的时间范围内,安全地将这个处理过程结束是不可行的 因此,考虑到这一点,在我开始工作之前,是否有可能通过告诉windows我的应用程序即将繁忙来至少避免“无响应”这个绰号(对大多数用户来说,它读作“已崩溃”)?我相信在响应关闭请求时,会有类似的事情发生,你可以不断地向windows请求更多的时间,以避免它宣称你没有“及时关闭”C++ 避免";(没有回应)“;一次处理大量数据时在windows中添加标签,c++,windows,mfc,C++,Windows,Mfc,我偶尔需要从网络上处理一个包中的大量数据,这需要足够长的时间,当用户尝试与应用程序交互时,windows会在窗口标题中添加“(无响应)”字符串。我知道这是因为处理是在一个调用中完成的,以处理一条消息(在堆栈的某个位置),因此阻塞了消息泵。我也知道处理这个问题的理想方法是在一个单独的线程中异步处理数据,这样泵就可以继续运行,但是这是一个从上到下的单线程的大型桌面应用程序,在我们的时间范围内,安全地将这个处理过程结束是不可行的 因此,考虑到这一点,在我开始工作之前,是否有可能通过告诉windows我
<>我应该补充一下这是一个C++ MFC应用程序。 < P>我不认为Windows API能在这里帮助你。 或者,显示一个带有进度条的对话框并使其在单独的线程中运行如何
对话框上类似“此操作可能需要半小时”的文本也可能合适。您需要以某种方式将处理与消息处理交错。如果线程是不可能的,那么您可能需要考虑将处理分为多个阶段。一种方法是在您第一次收到数据包时进行一些处理,然后向应用程序发送一条消息,说“继续在这里处理”。当应用程序收到“continue processing here”消息时,它将执行更多的处理,并发送另一条“continue processing here”消息或完成处理 不过,有几点需要考虑:
我不知道这在应用程序的设计中是否可行,但这将是解决问题的一种方法。好的,首先我对Frederick的帖子投了更高的票,因为不管你喜欢与否,第二个线程可能是最好的方法 然而,如果你真的不想走这条路,你可以在你的应用程序内部循环中手动泵送消息队列。像这样的东西
int Refresh()
{
MSG msg;
if (PeekMessage (&msg, NULL, 0, 0,PM_NOREMOVE))
if ((msg.message == WM_QUIT)
||(msg.message == WM_CLOSE)
||(msg.message == WM_DESTROY)
||(msg.message == WM_NCDESTROY)
||(msg.message == WM_HSCROLL)
||(msg.message == WM_VSCROLL)
)
return(1);
if (PeekMessage (&msg, NULL, 0, 0,PM_REMOVE))
{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
return(0);
}
这实际上是我在重写类似于单独线程的东西之前使用的一段代码。基本上,我会查看队列,过滤掉不需要的消息,然后发布其他消息。它在某种程度上是有效的,但偶尔会造成一些令人讨厌的副作用,因此需要重写。如果你放弃一个线程,你很可能会担心发生其他用户操作,这可能取决于长时间运行的操作的结果(是的,并发性)。因此,进一步扩展Fredrick所说的,如果您确实剥离了一个新线程并设置了一个进度条,您可以将焦点锁定在进度条上,以阻止用户与应用程序的其余部分交互。这应该足以实现一个非常简单的第二个线程,而不必真正担心并发性,因为您实际上是通过禁用用户交互来锁定应用程序的其余部分。您不必对来自PeekMessage的消息执行任何操作。只需调用PeekMessage,您甚至不必从队列中删除或处理任何内容。只要每隔5秒左右调用一次,它就会使windows认为进程仍然有响应
另一种方法是在通知栏中显示一个单独的进程/线程,并通知用户该进程正忙于等待内部操作完成。您将在Visual Studio、SQL Server Management Studio等的更高版本中看到这些内容。假设一直占用时间的是数据的处理,而不是数据的接收(并且您很认真地避免线程,这很好),您可以:
如果您愿意,该对话框甚至可以有一个取消按钮。Win32在
user32.dll
中提供了一种方法
禁用调用GUI进程的窗口重影功能。窗口重影是Windows管理器的一项功能,允许用户最小化、移动或关闭没有响应的应用程序的主窗口
此外
//__ENABLE OR DISABLE MAIN DIALOG
void CMFCApplication1Dlg::enableMainDlg(bool enable)
{
this->EnableWindow(enable);
}
Application->ProcessMessages();
DWORD WINAPI WaitForCasablanca(LPVOID n)
{
// Get the handler to the event for which we need to wait in
// this thread.
HANDLE hEvent = OpenEvent(EVENT_ALL_ACCESS, false, "MyEvent");
if (!hEvent) { return -1; }
// Loop through and wait for an event to occur
// Wait for the Event
WaitForSingleObject(hEvent, INFINITE);
// No need to Reset the event as its become non signaled as soon as
// some thread catches the event.
CloseHandle(hEvent);
return 0;}
BOOL WINAPI DlgProc(HWND hDlg, UINT message, WPARAM,wParam, LPARAM lParam) ...
HANDLE hEvent = CreateEvent(NULL, false, false, "MyEvent");//create an event that will wait for casablanca ro authenticate
if (!hEvent) return -1;
// Create a Thread Which will wait for the events to occur
DWORD Id;
HANDLE hThrd = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)WaitForCasablanca, 0, 0, &Id);
if (!hThrd) { CloseHandle(hEvent); return -1; }
makeCasablancaRequest(...);
SetEvent(hEvent); //casablanca has finished signal the event to terminate
WaitForSingleObject(hThrd, INFINITE); //wait for thread to die
CloseHandle(hThrd);
CloseHandle(hEvent);
...}