一、前言
本文是HALCON的 programmers_guide(编程指南) 中的2.2章节,章节名直译是——用HALCON进行并行编程,实际上就是多线程编程嘛。因为HALCON是机器视觉软件,涉及图像处理,图像处理往往就会牵扯到多线程,所以这章非常重要。它会给你一些多线程编程的建议与参考。
二、HALCON并行编程
HALCON通过线程安全(thread-safe)和可重入(reentrant)来支持并行编程,即不同线程可同时调用HALCON算子而无需等待。不过,并非所有算子都是完全可重入的。本节会详细介绍HALCON的可重入性。此外,还会指出用HALCON多线程编程时应注意的问题。
文件目录example\c中的示例程序example_multithread1.c展示了如何使用HALCON/C进行多线程处理,以并行提取板子上不同类型的部件。
此外,HALCON提供了特殊的算子来同步线程。
2.1 深入可重入性⭐
HALCON算子的可重入性分不同等级:
-
reentrant(可重入的)
如果一个算子可以在不受调用数据影响的情况下同时被多个线程调用,那么它就是完全可重入的。请注意,当多个线程使用相同的数据对象时(如同一个图像变量),你必须特别小心。该情况下,你必须使用相应的并行编程机制(互斥锁、信号量)同步对该变量的访问。更好的做法是尽可能避免这种情况,即使用局部变量。这不是HALCON特有的问题,而是并行编程普遍存在的问题。
-
local(局部的)
标记为 local 的算子应仅从实例化相应对象的线程中调用。 -
single write multiple read(单写多读)
仅当不同调用线程在处理不同数据时,才能同时调用的某些组的算子。尽管这种线程行为通常是不推荐的,但HALCON并不会主动阻止它(因为可以节省一部分性能开销)。这意味着,如果你(没注意、不小心)用相同数据同时调用这些算子时,虽然没有线程会阻塞,但可能会得到不想要的结果。
-
mutually exclusive(互斥的)
有些算子无法被多个线程同时调用,但可以与其它HALCON算子并行执行。 -
exclusive(独占的)
有一些组的算子是由HALCON独占执行,也就是说,在执行这些算子时,所有其它线程都无法调用其它HALCON算子。 -
independent(独立的)
还有的算子完全独立于其它算子执行,即使是独占的算子。
正如前面所述,在参考手册中HALCON算子的描述包含了一个叫做“Parallelization”的项,用于指定在使用HALCON时的行为。该项根据上面描述指定了可重入性的级别(没找到,大概是下图中框出的信息?)。
2.2 多线程编程设计问题
通常,多线程编程要考虑下面问题:
- 线程数量≤处理器或核的数量
如果你使用的线程数大于处理器或处理核心的数量,由于同步的开销,应用程序实际上可能比之前更慢。请注意,仅统计持续工作的相关线程。 - 局部变量
尽可能使用局部变量,即在使用它们的线程中实例化变量。若多个线程使用相同的变量,则必须使用适当的并行编程构造(mutex互斥锁、semaphore信号量)同步它们对变量的访问(详细信息,参阅编程语言文档)。
在使用HALCON时,请注意以下问题:
- Initialization(初始化)
在多线程程序中并行调用HALCON算子之前,必须先独占式调用一个算子。为了让HALCON初始化其内部结构,这是必要的。 - I/O与可视化
请记住,创建或删除文件的算子是独占的(exclusive),即其它线程必须等待。程序员必须确保线程不会同时访问同一文件(或句柄(handle))。 - 多线程与自动并行化
若你在多线程程序中显式地平衡多个处理器或核心的负载,建议关闭自动并行化机制,以获得最佳性能(或减少使用的线程数,以使线程总数不超过处理器或核心数)。
2.3 多线程算子
在算子部分“System.Multithreading”中,HALCON提供了用于创建和使用同步对象的算子,例如互斥锁、事件、条件变量和屏障(barrier)。使用它们,你可以以平台无关的方式同步线程。
2.4 示例
目前,HALCON提供了以下并行编程示例(相对路径为%HALCONEXAMPLES%):
HALCON/.NET
- c#\MultiThreading (C#)
在三个线程中执行图像采集、处理和显示。 - hdevengine\c#\MultiThreading (C#)
使用HDevEngine,通过两个线程并行执行相同的HDevelop过程。 - hdevengine\c#\MultiThreadingTwoWindows (C#)
executes different HDevelop procedures in parallel by two threads using HDevEngine
使用HDevEngine,通过两个线程并行执行不同的HDevelop过程。
三、结语
实话讲,看完这节,并没有给我带来很大的启发。
印象比较深的应该是可重入性的分级,因为几乎每个算子的执行信息(Execution information)中都有一项多线程类型,通过该类型可以知道算子在多线程下调用的注意事项(程度)。