0

我正在开发小型 gif 图像查看器程序。由于解码整个 gif 需要几秒钟,我决定使用单独的线程在后台对其进行解码,并且(经过适当的调整)让程序在启动后开始平滑地显示 gif。使用第一种方法,程序等待(几秒钟)直到整个 gif 被解析,然后开始显示它,一切正常。使用第二种方法,程序在加载第一帧后立即开始显示 gif,然后以怪诞的方式(因为尚未调整)显示已加载的帧,直到所有帧都加载完毕。我在这两种方法中使用完全相同的解析和显示函数,但问题是,在线程方法中,线程完成并退出后,gif显示速度稍慢,where 应该与第一种方法中的相同,因为线程已经退出。所以我的问题是,线程是否有可能对进程产生永久性影响,即使它们已经完成?(我确定他们正在退出,因为我使用 CloseHandle 函数并且它返回 1。)

我也会复制一些代码,但它们是非常聪明的摘录,不多说:

请注意,我将帧转换为 hbitmap 以在 window
First 方法上显示它们:

gifImage->findFrames();
frames_bitmaps=(HBITMAP *)malloc(gifImage->getFramesQuantity()*sizeof(HBITMAP));
for(int i=0;i<gifImage->getFramesQuantity();i++)
{
    frames_bitmaps[i]=gifImage->getFrame(i)->convertToDIB(hwnd);
}
startDisplay();

第二种方法:

//"main" function:
DWORD id1,id2;
findThread=CreateThread(NULL, 0, startFindFrames, (void*) this, 0, &id1);
fillThread=CreateThread(NULL, 0, startfillBitmaps, (void*) this, 0, &id2);

//the actual functions (these in CreateThread func are static for compatibility and contain the following ones):
void GifExplodeWindow::findFrames()
{
    gifImage->findFrames();
    loading_done=1;
}

void GifExplodeWindow::fillBitmaps()
{
    while(!loading_done)
    {
        int current_quantity=gifImage->getFramesQuantity();

        if(filled_bitmaps<current_quantity)
        {
            frames_bitmaps=(HBITMAP *)realloc(frames_bitmaps,current_quantity*sizeof(HBITMAP));

            for(;filled_bitmaps<current_quantity;filled_bitmaps++)
            {
                frames_bitmaps[filled_bitmaps]=gifImage->getFrame(filled_bitmaps)->convertToDIB(hwnd);


                if(filled_bitmaps==0 && current_quantity!=0)
                {   
                    display_state=PREVIEW;
                    changeDisplay();
                }

                filled_bitmaps++;
            }
        }

        Sleep(50);
    }
}   

我最初编写代码只是为了让它工作,当我解决我的问题时我会纠正它,但现在唯一重要的是它的作用

4

3 回答 3

1

推荐:

完成的线程对winapi中的主程序有影响吗?

你可以说得更详细点吗?你具体指的是什么样的效果?

我建议通过附加代码示例来扩展问题,详细说明您的问题是什么。

在我看来,这只是一个太笼统的问题。

答案:

看完你的问题,我得出了和其他人一样的结论,那就是你可能没有做正确的线程同步。

您会看到,使用时CloseHandle,您不会关闭线程,也不会启动线程关闭。

我希望事情有那么容易:)

来自 MSDN(请参见此处的备注部分:http: //msdn.microsoft.com/en-us/library/windows/desktop/ms724211%28v=vs.85%29.aspx):

关闭线程句柄不会终止关联的线程或删除线程对象

CloseHandle只是关闭句柄,但您需要在代码中添加额外的指令来关闭您的线程函数。

这通常通过设置的事件对象来完成,当您想要停止线程时,或者您可以使用布尔变量。

从您的问题内容来看,我认为这些是您最好的选择。

此外,您还应该阅读有关线程同步的信息,如果您的线程函数可以在程序中多次启动并且所有/某些这些函数可以访问和修改相同的资源(在您的情况下是 GIF 图片)。

阅读您的问题,我得出结论,您的线程函数没有GUI,也不需要显示MessageBox或对话框。因此可以安全地假设,您的线程类型就是通常所说的“工作线程”。

由于您的问题对我来说并不完全清楚,我只假设您在没有足够经验的情况下处理了这个话题。

其中一些文章/链接可能会帮助您解决问题:

http://www.codeproject.com/Articles/552/Using-Worker-Threads

http://msdn.microsoft.com/en-us/library/windows/desktop/ms684841%28v=vs.85%29.aspx

在上一篇文章中,您可能希望从以下内容开始:

http://msdn.microsoft.com/en-us/library/windows/desktop/ms686937%28v=vs.85%29.aspx

更具体地说http://msdn.microsoft.com/en-us/library/windows/desktop/ms682516%28v=vs.85%29.aspx

另外,请注意同步对象,您可能会发现互斥锁和临界区很方便:

http://msdn.microsoft.com/en-us/library/windows/desktop/ms686967%28v=vs.85%29.aspx

这两个代码示例也可能对您有所帮助:

http://msdn.microsoft.com/en-us/library/windows/desktop/ms687055%28v=vs.85%29.aspx

http://msdn.microsoft.com/en-us/library/windows/desktop/ms686915%28v=vs.85%29.aspx

总结:

我给了你很多链接,所以我会尽量让你更容易,在本节中,尽我所能:

您的主线程(GUI、对话框...)应该启动线程函数,并等待它完成。

为了让主线程(GUI、对话框)知道你的线程函数何时完成,它必须从它那里接收某种通知。

PostMessage这通常是通过API 或通过设置事件对象从线程函数发送到主线程(GUI、对话框)的自定义消息来完成的。

然后,您必须在主线程(GUI、对话框...)中等待该线程函数使用 WaitForSingleObject 退出,如果您启动了多个线程,则使用 WaitForMultipleObjects 退出。

只有这样,你才能关闭线程句柄。

此外,为了安全起见,最好将线程句柄设置为 NULL。

您应该尝试通过 Internet 找到这本书:

编程 Windows 第 5 版,作者:Charles Petzold。

在第 20 章中,你有一个代码示例,它按照我描述的方式同步线程执行,所以试着找到那本书,从朋友那里买/借……

(也许单独的源代码可以帮助你,从这里下载:http: //www.charlespetzold.com/books.html,我认为它是免费的,但检查一下,以防万一)。

另外,一个重要的注意事项:

不要使用TerminateThreadExitThreadAPI 关闭您的线程。线程函数应该正常返回,不应该被强行中止。

通过 Petzold 书中的代码示例,并通过阅读这些链接和我的答案,您应该了解线程同步的工作原理,也许您将能够解决您的解决方案。

如果您还有其他问题,请向我寻求帮助,我会尽力帮助您。

祝你好运!

问候。

于 2013-09-23T21:58:10.510 回答
0

问题出在代码上,非常可耻的错误。在 fillBitmaps() 函数的内部 for 循环中,我在每个循环中将 fill_bitmaps 变量增加两次,这导致了奇怪的显示。

于 2013-10-23T18:18:38.647 回答
0

“我确定他们正在退出,因为我使用 CloseHandle 函数并且它返回 1”

它不是那样工作的。CloseHandle 对线程没有影响,并且不会告诉您有关线程的任何信息。如果您需要主线程知道辅助线程何时完成,您必须提供来自辅助线程的一些信号。一种方法是让该线程在完成时使用 PostMessage 通知主线程。

于 2013-09-20T17:59:53.933 回答