如何使用“停止按钮”停止一个进程

8
我创建了一个带有两个按钮的简单窗口,第一个按钮调用一个长时间运行的函数,第二个按钮将变量"stop"的值设置为TRUE,该变量最初设置为FALSE。
我的意图是,通过按下第一个按钮,它会运行一个长时间的进程,该进程控制每个循环中stop变量是否设置为TRUE或FALSE,如果该值为TRUE,则函数应返回,因此该进程被停止。
...

static BOOL stop = FALSE;   // My variable defined somewhere

...

int longProcess ()   // My function
{
    while(stop == FALSE) {
         // do something
    }
    return 0;
}

...

switch (msg)
{
    case WM_CREATE:
    {
                            ...

        Button1 = CreateWindowEx(0, 
                                         TEXT("BUTTON"),
                                         TEXT("Start"),
                                         WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
                                         100, 100, 100, 20,
                                         hWnd,
                             (HMENU)BUTTON_START,
                             NULL,
                                         NULL);

        Button2 = CreateWindowEx(0,
                           TEXT("BUTTON"),
                       TEXT("Stop"),
                       WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
                       200, 200, 100, 20,
                               hWnd,
                               (HMENU)BUTTON_STOP,
                               NULL,
                               NULL);
                             ...

    }
    break;

    case WM_COMMAND:
    {
        switch (LOWORD(wParam))
        {

                        case BUTTON_START:
                            longProcess();   // Starts the process
                break;

                        case BUTTON_STOP:
                            stop = TRUE;  // Should stop the process
                break;

        }
    }
    break;

    ...

}

问题在于,当我按下第一个按钮时,进程开始正常运行,但是当我按下第二个按钮以停止进程时,什么也没有发生,我注意到只有在进程结束后才将停止变量设置为TRUE。我认为这可能与消息队列有关的问题...

最好的解决方案是什么? 在那里调用longProcess()是正确的方法吗?(我是新手 :))

谢谢!


欢迎来到并发编程的世界! - J. Polfer
5个回答

13
你需要在单独的线程上运行长时间的进程,你的方法应该可行。
这意味着,不要直接在“开始”按钮点击事件中调用 longProcess 函数,而是创建一个线程并在其上运行长时间的进程。
发生的情况是,你的长时间进程正在阻塞UI线程,而UI线程负责处理UI事件。因此,在 longProcess() 完成之前,无法处理“停止”按钮点击事件。

5
在Delphi中,我们有Application.ProcessMessages()函数,它基本上处理所有待处理的消息并返回。您可以将此行放入循环中,以使UI更加响应灵敏。
有了这样的功能,您可以做到这一点:
while(stop == FALSE) {
     // do something
    ...

    ProcessPendingMessages();
}

编辑: 如果您不想将代码拆分到单独的线程中-快速且有用的解决方法


2
在Windows中,它是GetMessage/DispatchMessage - sje397

3

如何使用PeekMessage

int longProcess ()   // My function
{
    while(stop == FALSE) 
    {
        // do something

        while (PeekMessage(&msg, hwnd,  0, 0, PM_NOREMOVE)) 
        { 
            // check for the stop button
            if ((msg.message == WM_COMMAND) && (LOWORD(wParam) == BUTTON_STOP))
                stop = TRUE;
            } 
        } 
    }
}

3

至少,你需要使用volatile关键字来声明变量。但是最好的方法是使用事件。使用CreateEvent()初始化它,使用SetEvent()来发出停止信号,使用WaitForSingleObject()和0超时进行测试。


1
作为 AOI Karasu 答案的变体,MFC 有 CWinThread::PumpMessage()。
我在工作线程循环中使用它来保持响应。它非常好用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接