多线程概述 - (中文版)

这是wxWidgets论坛的中文版本。在这里,您可以用您的母语汉语讨论上面任一子论坛所涉及的所有关于wxWidgets的话题。欢迎大家参与到对有价值的帖子的中英互译工作中来!
Post Reply
ChunJiu
Knows some wx things
Knows some wx things
Posts: 35
Joined: Thu Jun 05, 2014 2:52 pm

多线程概述 - (中文版)

Post by ChunJiu » Thu Jun 05, 2014 3:41 pm

因学习需要,译为中文版本,作为学习笔记。 :D
醇酒 2014.6.5

多线程概述

wxWidgets提供了一套完整的多线程应用程序(MT)所需的类封装对象:wxThread类本身和不同的同步对象 - 互斥体(请参阅wxMutex)和临界区(请参阅wxCriticalSection)和条件(请参阅wxCondition)。 wxWidgets中的线程API类似于POSIX1.c线程API(又名pthreads),虽然几个函数有不同的名字和一些特征的灵感来自Win32的线程API在那儿也不错。

这些类希望能让编写MT的程序变得更加容易,并且提供了一些额外的错误检查(相对于原生 – 即Win32或Posix – 线程API),但它是一个非保证的承诺,尤其是对大型项目。在启动一个应用程序的MT(或开始将MT功能添加到现有的一个)之前,它是值得问一下自己,是否实现相同的功能没有更简单和更安全的方式了?当然,在某些情况下,线程真的有意义(经典的例子是服务器应用程序为每个新的客户端运行一个新的线程),但另一些可能是矫枉过正。在另一方面,计算机硬件的近期发展表明朝向多核系统的一个重要趋势,这使得利用多线程变得更好(例如将一个艰巨的任务根据系统的CPU(内核)报告来拆分成多个线程,参见wxThread::GetCPUCount)。

为了实现非阻塞的操作,又不想使用多线程则有两种可能的实现选择:

[*] 使用wxIdleEvent(例如执行长计算,同时更新一个进度对话框)
[*] 做完所有事情,但调用wxWindow::Update()或wxApp::YieldFor(wxEVT_CATEGORY_UI)注来定期更新屏幕。

注意:这个wxApp::YieldFor(wxEVT_CATEGORY_UI)在wxWidgets中没有找到,可能只是早期版本的描述,属于历史遗留的文字。

但如果选择了使用应用程序中的线程,请仔细阅读本概述的以下部分。

另请参阅:
wxThread, wxThreadHelper, wxMutex, wxCriticalSection, wxCondition, wxSemaphore

对于多线程应用程序的重要注意事项

在写一个多线程的应用程序时,有个很重要的建议,绝对不要在辅助线程中调用GUI函数。使用一个GUI线程和几个工作线程,并使用事件来和主要的一个通信的设计会更加健壮,并且会避免大量的问题(例如:Win32下的一个线程只能访问它自己创建的GDI对象,像笔、画刷、设备上下文,而不能访问别的线程创建的GDI对象)。

对于辅助线程和主线程间的通信,可用wxEvtHandler::QueueEvent或短版本的wxQueueEvent。这些函数有一个线程安全的实现,使得它们可以被用来将它们从一个线程发送事件到另一个。但没有内置的方法来发送消息到一个工作线程,只能使用可用的同步类来实现符合需要的解决方案。特别要注意的是:从wxThread和wxEvtHandler派生的类是无法将消息发送给它的,实际上这是行不通的。推荐使用wxThreadHelper,因为它极大地简化了通信和资源共享。最好也要看看wxThread文档中有关辅助线程的重要资料和它们的删除。

最后,请记住:如果在代码中直接、或间接地使用了 wxEventLoopBase::YieldFor()(比如说通过wxProgressDialog),那么有可能面临两个重入问题、和造成事件处理的顺序混乱问题。要解决的最后一个问题可以使用wxThreadEvent:这得益于wxThreadEvent::GetEventCategory函数的实现,wxThreadEvent类实际上并没有被wxEventLoopBase::YieldFor()处理,除非设定了一个专门的标记 wxEVT_CATEGORY_THREAD。

另请参阅用于演示主、副线程之间的一些简单的交互样本线程的范例。

Post Reply