Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/windows/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 避免";(没有回应)“;一次处理大量数据时在windows中添加标签_C++_Windows_Mfc - Fatal编程技术网

C++ 避免";(没有回应)“;一次处理大量数据时在windows中添加标签

C++ 避免";(没有回应)“;一次处理大量数据时在windows中添加标签,c++,windows,mfc,C++,Windows,Mfc,我偶尔需要从网络上处理一个包中的大量数据,这需要足够长的时间,当用户尝试与应用程序交互时,windows会在窗口标题中添加“(无响应)”字符串。我知道这是因为处理是在一个调用中完成的,以处理一条消息(在堆栈的某个位置),因此阻塞了消息泵。我也知道处理这个问题的理想方法是在一个单独的线程中异步处理数据,这样泵就可以继续运行,但是这是一个从上到下的单线程的大型桌面应用程序,在我们的时间范围内,安全地将这个处理过程结束是不可行的 因此,考虑到这一点,在我开始工作之前,是否有可能通过告诉windows我

我偶尔需要从网络上处理一个包中的大量数据,这需要足够长的时间,当用户尝试与应用程序交互时,windows会在窗口标题中添加“(无响应)”字符串。我知道这是因为处理是在一个调用中完成的,以处理一条消息(在堆栈的某个位置),因此阻塞了消息泵。我也知道处理这个问题的理想方法是在一个单独的线程中异步处理数据,这样泵就可以继续运行,但是这是一个从上到下的单线程的大型桌面应用程序,在我们的时间范围内,安全地将这个处理过程结束是不可行的

因此,考虑到这一点,在我开始工作之前,是否有可能通过告诉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等的更高版本中看到这些内容。

    假设一直占用时间的是数据的处理,而不是数据的接收(并且您很认真地避免线程,这很好),您可以:

  • 在当前正在处理消息的函数中,创建一个模式对话框,显示“请稍候”消息(或将其隐藏、变小,等等)。将正在处理的数据复制(或发送指针等)到该对话框的成员变量
  • 在模式对话框中,向自己发布用户定义的消息以处理数据
  • 在对话框的消息处理程序中,处理一个“单位”的工作。跟踪下一个“工作单元”是什么。再次发布相同的消息
  • 重复此post消息“循环”,直到完成。关闭对话框
  • 模式对话框的性质将使您的应用程序保持“响应”,对应用程序以前的工作方式进行最小的中断或更改。模式循环的可重入性可能是一个问题,特别是当其中任何一个涉及WM_PAINT消息时。(有人断言过内部绘画代码吗?好时光,好时光…)


    如果您愿意,该对话框甚至可以有一个取消按钮。

    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);
                ...}