关于GUI下的多线程。我用了MsgWaitForMultipleObjects,可是为什么在线程工作的过程中不能关闭窗体呢。好急啊

时间:2021-10-14 16:22:31
我是在C++Builder下写的程序。可是那个版没人答复我。大家帮看看吧,反正是win32多线程,一样的。
第一个问题是点击关闭窗口没有反应:
void __fastcall TForm1::Button1Click(TObject *Sender)
{    
    DWORD tid;
    DWORD exitCode = 0;
    hRequestExitEvent = CreateEvent(NULL,true,false,NULL);
    if(!hcd)
       hcd = CreateThread(NULL,0,ListFile,(void *)this,0,&tid);
    else
    {
       SetEvent(hRequestExitEvent);  //外部终止工作线程
       CloseHandle(hcd) ;
       hcd = 0;
       hcd = CreateThread(NULL,0,ListFile,(void *)this,0,&tid); //线程重新启动
    }
    while(!quit)
    {
       MSG msg;
       DWORD result;
       result = MsgWaitForMultipleObjects(1,&hcd,false, 3000, QS_ALLINPUT);
       if(result == WAIT_OBJECT_0 + 1)
       {
          while(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
          {
             if(msg.message == WM_QUIT)  //就是这里,如果是关闭窗口的消息就退出while
             {
                quit = true;
                exitCode = msg.wParam; 
                break;
             }    
             TranslateMessage(&msg);
             DispatchMessage(&msg);
          }
       }
       else
       {
          if (WaitForSingleObject(hcd,INFINITE)==WAIT_OBJECT_0)
          {
             CloseHandle(hcd);
             hcd = 0;
             break;
          }
       }
    }
}

线程函数:
unsigned long WINAPI TForm1::ListFile(void * CallPam)
{
   TForm1 *tem = (TForm1 *)CallPam;
    int i = 0;
    while(i++ < 10000)
    {
      tem->Memo1->Lines->Add(IntToStr(i));      
      if(WaitForSingleObject(tem->hRequestExitEvent,0) != WAIT_TIMEOUT)       
      {
         tem->Edit1->Text = "Received reauest to terminate";
         return DWORD(-1);
      }
    }
    return 0;
}

代码就是这样的了。
而且我在C++Builder中重载了WndProc函数捕捉WM_QUIT消息也是同样的问题。

第二个问题:在下面这段代码中
    if(!hcd)
       hcd = CreateThread(NULL,0,ListFile,(void *)this,0,&tid);
    else
    {
       SetEvent(hRequestExitEvent);  //外部终止工作线程
       CloseHandle(hcd) ;
       hcd = 0;
       hcd = CreateThread(NULL,0,ListFile,(void *)this,0,&tid); //线程重新启动
    }
我想达到的目的是:如果工作线程正在运行则停止该线程,并重新启动线程(因为变量改变了,需要重新工作),但是好象没有能够立即启动,也就是说else里的hcd = CreateThread(NULL,0,ListFile,(void *)this,0,&tid);没有产生效果,但确实是执行到了。请问这是怎么回事啊。

我一会再到VC中试试。但本人VC不熟,所以还请各位高手包涵了。
很急,谢谢了!

10 个解决方案

#1


直接一点,用TerminateThread终止了那个线程算了。

#2


确定你的线程结束了

#3


线程确实是结束了
但是窗口要关闭两次才能关掉

#4


关闭两次,关闭是怎么处理的

#5


C++ builder中的APPLICATION也有窗体,是不可见的.

#6


第一个问题:
if(msg.message == WM_QUIT) 
{
    quit = true;
    exitCode = msg.wParam; 
    break;
}    
当程序获得WM_QUIT消息时,被你的这个消息循环截获了,于是你break了这个while消息循环,但是问题是系统的另外那个消息循环并没有停止,继续在运行。这就是为什么需要关闭两次才可以的原因。

你试试这样修改:
if(msg.message == WM_QUIT) 
{
    quit = true;
    exitCode = msg.wParam; 
    PostMessage(hwnd, msg, NULL, NULL); // 手工添加一个QUIT消息,终止系统消息循环。
    break;
}    

#7


第二个问题:
hRequestExitEvent = CreateEvent(NULL,true,false,NULL);
你的Event对象是手工复位的(CreateEvent的第二个参数是true),这意味你的Event对象如果不手工调用 ResetEvent函数,会一直处于激发状态。
也就是说,你创建的第二个线程在运行后,检测到hRequestExitEvent的状态是激发态后马上就退出了,这也就是为什么第二个线程没有起作用的原因。

你可以试试这样修改:
hRequestExitEvent = CreateEvent(NULL,false,false,NULL);

但是这样仍然有问题:因为你不能够确定到底是哪一个线程先被分配到时间片。所以唯一的解决方案还是老老实实等待第一个线程退出后在Create第二个线程(记得如果是在UI线程中,一定使用MsgWaitForMultipleObjects函数)

#8


谢谢shootingstars(有容乃大,无欲则刚)的解答,已经搞定

但仍然不大理解你第二个问题的意思:"因为你不能够确定到底是哪一个线程先被分配到时间片".这句话什么意思。

#9


如果按照shootingstars(有容乃大,无欲则刚)的说法。
如果我想实现立即结束线程并重新启动,就没有其它办法了吗?难道非得要等待第一个线程结束?

#10


但仍然不大理解你第二个问题的意思:"因为你不能够确定到底是哪一个线程先被分配到时间片".这句话什么意思。
---------------------------------------------------------------------
比如你的主线程是0号线程,原来启动的那个线程是1号线程,新启动的是2号线程.
在你执行完SetEvent(hRequestExitEvent); 这个语句的若干毫秒内,CPU会切换到1号或者2号线程。(注意:CreateThread建立线程后,新建立的线程并不一定会马上得到运行的时间)。如果CPU切换到2号线程,这个结果是你不想看到的。

如果你确实不想等待第一个线程结束后再启动第二个线程,你或许可以用一个Event数组?每个Event对应一个线程。(记得在线程退出之前关闭对应的Event)

#1


直接一点,用TerminateThread终止了那个线程算了。

#2


确定你的线程结束了

#3


线程确实是结束了
但是窗口要关闭两次才能关掉

#4


关闭两次,关闭是怎么处理的

#5


C++ builder中的APPLICATION也有窗体,是不可见的.

#6


第一个问题:
if(msg.message == WM_QUIT) 
{
    quit = true;
    exitCode = msg.wParam; 
    break;
}    
当程序获得WM_QUIT消息时,被你的这个消息循环截获了,于是你break了这个while消息循环,但是问题是系统的另外那个消息循环并没有停止,继续在运行。这就是为什么需要关闭两次才可以的原因。

你试试这样修改:
if(msg.message == WM_QUIT) 
{
    quit = true;
    exitCode = msg.wParam; 
    PostMessage(hwnd, msg, NULL, NULL); // 手工添加一个QUIT消息,终止系统消息循环。
    break;
}    

#7


第二个问题:
hRequestExitEvent = CreateEvent(NULL,true,false,NULL);
你的Event对象是手工复位的(CreateEvent的第二个参数是true),这意味你的Event对象如果不手工调用 ResetEvent函数,会一直处于激发状态。
也就是说,你创建的第二个线程在运行后,检测到hRequestExitEvent的状态是激发态后马上就退出了,这也就是为什么第二个线程没有起作用的原因。

你可以试试这样修改:
hRequestExitEvent = CreateEvent(NULL,false,false,NULL);

但是这样仍然有问题:因为你不能够确定到底是哪一个线程先被分配到时间片。所以唯一的解决方案还是老老实实等待第一个线程退出后在Create第二个线程(记得如果是在UI线程中,一定使用MsgWaitForMultipleObjects函数)

#8


谢谢shootingstars(有容乃大,无欲则刚)的解答,已经搞定

但仍然不大理解你第二个问题的意思:"因为你不能够确定到底是哪一个线程先被分配到时间片".这句话什么意思。

#9


如果按照shootingstars(有容乃大,无欲则刚)的说法。
如果我想实现立即结束线程并重新启动,就没有其它办法了吗?难道非得要等待第一个线程结束?

#10


但仍然不大理解你第二个问题的意思:"因为你不能够确定到底是哪一个线程先被分配到时间片".这句话什么意思。
---------------------------------------------------------------------
比如你的主线程是0号线程,原来启动的那个线程是1号线程,新启动的是2号线程.
在你执行完SetEvent(hRequestExitEvent); 这个语句的若干毫秒内,CPU会切换到1号或者2号线程。(注意:CreateThread建立线程后,新建立的线程并不一定会马上得到运行的时间)。如果CPU切换到2号线程,这个结果是你不想看到的。

如果你确实不想等待第一个线程结束后再启动第二个线程,你或许可以用一个Event数组?每个Event对应一个线程。(记得在线程退出之前关闭对应的Event)