LabVIEW使用执行系统和优先级的建议
在大多数应用程序中,无需使用优先级或者除标准执行系统以外的执行系统,标准执行系统会自动对VI进行多任务处理。默认情况下,所有VI都在标准执行系统的一般优先级上运行。在多线程应用程序中,由一个单独的线程来处理用户界面,所以VI和用户界面交互是相互独立的。在单线程应用程序中,执行系统轮流执行用户界面交互和VI,并给出类似结果。
通常优先级执行的最好的方法是在应用程序的优先级循环中用等待函数放慢较低优先级的执行速度。这一点在用户界面VI的循环队列中非常有用,因为100到200毫秒的延时对用户而言是很难察觉的。
如果使用优先级,则必须非常小心。如果在设计中使用了较高的优先级,则必须考虑为那些次要部分增加等待,使它们和较低优先级的任务共享执行时间。
当其它任务变化时,应留意操作全局变量、局部变量或者其它外部资源。使用同步技术,比如功能全局变量或信号量(semaphore)来保护这些资源。
同步访问全局变量、局部变量以及外部资源
因为执行系统可以几个任务并行运行,因此必须保证以适当的顺序访问全局变量、局部变量或资源。
防止竞争状态
有几种方法可以防止竞争状态。最简单的方法是整个应用程序中只通过一个地方修改全局变量。
在单线程应用程序中,使用子程序级VI读出或者写入全局变量不会造成竞争状态,因为子程序级VI不与其它VI共享执行线程。在多线程应用程序中,子程序级不保证对全局变量的唯一访问,因为当另一个VI在另一个线程上运行时,它能够同时访问全局变量。
功能全局变量
功能全局变量是一种非重入VI,使用循环和不初始化的移位寄存器来存储全局性数据。功能性全局变量通常有一个动作输入参数,用于指定VI执行的任务。可使用功能全局变量保护访问变量操作的关键代码,避免全局变量引起的竞态。使用全局变量时,一部分代码读取变量值,修改后将值写回变量,如果这时另一段代码也在访问共享变量,可能会发生竞态。使用功能全局变量可以避免竞态。例如,如果代码包含读取、递增、写入数据至内存、更新数据库、修改文件等操作,功能全局变量可保护这些代码,防止引起竞态。
下列图示是功能全局变量的一个简单范例。VI在While循环中使用一个未初始化移位寄存器,保存操作的结果。该范例中的操作是初始化、读取、递增和递减。
每次调用这个VI时,循环中的代码只执行一次。根据操作参数,循环中的选择结构根据移位寄存器的值进行初始化、保持不变、递增或递减。
功能全局变量不仅能实现简单的全局变量,也能实现更复杂的数据结构,例如,堆栈或队列缓存。功能全局变量还能用于保护对全局资源的访问,例如,文件、仪器、数据采集设备等无法通过全局变量表示的全局资源。除非VI为可重入VI,否则对功能全局变量的调用只能按顺序执行。
使用功能全局变量能解决大多数同步问题,因为功能全局VI确保一次只有一个调用者修改数据内容。功能全局变量的缺点是如要更改变量所代表资源的修改方式时,必须修改功能全局VI的程序框图并增加新的操作。在一些应用程序中,频繁修改全局资源将带来诸多不便。在这种情况下,可以使用信号量保护对全局资源的访问来设计应用程序。
数据通信方法主页
信号量
信号量是一种互斥量,用来保护对共享资源(例如,某全局变量)进行访问的一个对象。访问共享资源的代码称为关键性代码。在同一时间,只有一定数量的任务可以访问信号量。信号量以此方式保护对重要部分的访问。通常情况下,一次只有一个任务可以访问被通用信号量保护的临界段。但是,可配置信号量允许一个以上的任务来访问关键性代码。
信号量大多数使用案例的步骤如下:
找到关键性代码—信号量通常用于控制访问共享资源的代码。例如,有多个子VI读取同一个全局变量,需保证这些代码不会同时执行,以避免发生竞态。在该范例中,每段读取或写入全局变量的代码都是关键性代码。常见的关键性代码还有文件、设备I/O等。
创建关键代码共享的信号量—使用获取信号量引用VI创建一个新的信号量或按名称获取一个已经存在的信号量。默认情况下,信号量每次只允许一个任务访问。如要信号量能同时接受多个访问,需在获取信号量引用VI的大小输入端指定任务的数量。
在每个关键代码之前先获取对信号量的访问—使用获取信号量VI获取对信号量的访问。如信号量正被其他任务使用,数据流将在获取信号量VI处挂起,直到相关任务释放该信号量。当信号量被占用后,其他任务只能在信号量被释放后才能获取该信号量。因此,获取信号量VI和释放信号量VI之间的代码保证能完成执行。执行完毕后,其他代码才能开始执行。
释放信号量给其他关键性代码—使用释放信号量VI将信号量释放给其他正在等待信号量的代码。
释放信号量引用—使用释放信号量引用VI释放对信号量的引用。当所有任务完成使用信号量后,请确保释放对信号量的引用,以保证系统资源被有效利用。
注: 有些高级的信号量使用不要求在一段代码中重复获取和释放信号量。
关于使用“获取信号量引用”VI和“释放信号量引用”VI的范例,见labview\examples\Synchronization\Semaphore中的Simple Semaphore VI。
下图显示了如何使用信号量来保护临界段。另一个VI创建了信号量并将引用传递给这些子VI。信号量的大小为1,表示一次只能有一个任务访问信号量。
上述程序框图都包含一段访问同一个全局变量count的关键性代码。所以,所有程序框图都使用一个信号量。程序框图开始执行关键性代码之前,都会调用获取信号量VI检测其他程序框图是否已经获取了信号量。如果信号量忙,获取信号量VI将等待直到信号量可用。信号量可用时,获取信号量VI的超时接线端返回FALSE,表示程序框图可以执行其关键性代码。当程序完成其关键代码时,释放信号量VI释放信号量,允许其他等待程序重新开始执行。
信号量的生命周期
只要非空闲的顶层VI引用了某个信号量,信号量就一直在内存中。如顶层VI为空闲,LabVIEW将释放该VI的全部信号量引用,包括顶层VI的子VI中的引用。如LabVIEW释放上一个引用给某命名信号量,LabVIEW将销毁信号量。因为只能获取引用至一个未命名信号量的引用,当顶层VI空闲时,LabVIEW将销毁一个未命名信号量。如要在多个顶层VI之间使用信号量,需为信号量命名并从顶层VI调用“获取信号量引用”VI,这样每个VI就有了对信号量的唯一引用。
需要说明的是,上述的例程和文档,都是可以下载的,双击即可打开,其中压缩文件是可以采用粘贴复制的方式,拷贝到硬盘上。这不是图片,各位小伙伴看到后尝试一下,这个问题就不用加微信咨询了。有关LabVIEW编程、LabVIEW开发等相关项目问题,可联系我们。