微波EDA网,见证研发工程师的成长!
首页 > 测试测量 > 测试测量技术文库 > LabWindows?/CVI中的多线程技术

LabWindows?/CVI中的多线程技术

时间:12-23 来源:互联网 点击:

要运行的时候,具有最高优先级的线程首先运行。

Windows将优先级分类。同一进程中的所有线程拥有相同的优先级类别。同一进程中的每个线程都有着与进程优先级类别相关的优先级。可以调用Windows SDK中的SetProcessPriorityClass函数来设定系统中线程的优先级。

NI公司不推荐用户将线程的优先级设为实时优先级,除非只在很短时间内这样做。当进程被设为实时优先级时,它运行时系统中断会被阻塞。这会造成鼠标、键盘、硬盘及其它至关重要的系统特性不能工作,并很可能造成系统被锁定。

如果你是使用CmtScheduleThreadFunctionAdv函数来将函数调度到线程池中运行,那么还可以指定执行所调度函数的线程的优先级。线程池在运行被调度的函数前会改变线程优先级。在函数结束运行后,线程池会将线程优先级恢复到原来的优先级。可使用CmtScheduleThreadFunctionAdv函数来在默认的和自定义的线程池中指定线程的优先级。

在创建自定义的LabWindows/CVI Utility Library线程池(调用CmtNewThreadPool函数)时,可以设定池中各线程的默认优先级。

9. 消息处理

每个创建了窗口的线程必须对Windows消息进行处理以避免系统锁定。用户界面库中的RunUserInterfacefunction函数包含了处理LabWindows/CVI用户界面事件和Windows消息的循环。用户界面库中的GetUserEvent和ProcessSystemEventsfunctions函数在每次被调用时对Windows消息进行处理。如果下列情况中的之一被满足,那么程序中的每个线程都需要调用GetUserEventor和ProcessSystemEventsregularly函数来处理Windows消息。

  • 线程创建了窗口但没有调用RunUserInterface函数。
  • 线程创建了窗口并调用了RunUserInterface函数,但是在返回到RunUserInterface循环前需要运行的回调函数占用了大量时间(多于几百毫秒)。

但是,在代码中的某些地方不适合用于处理Windows消息。在LabWindows/CVI的用户界面线程中调用了GetUserEvent、ProcessSystemEvents或RunUserInterface函数时,线程可以调用一个用户界面回调函数。如果在用户界面回调函数中调用这些函数之一,那么线程将调用另外一个回调函数。除非需要这样做,否则这种事件将产生不可预知的行为。

Utility Library中的多线程函数会造成线程在循环中等待,允许你指定是否在等待线程中对消息进行处理。例如,CmtWaitForThreadPoolFunctionCompletion函数中有个Option参数,可以使用它来指定处理Windows消息的等待线程。

有的时候,线程对窗口的创建不是那么显而易见的。用户界面库函数如LoadPanel、CreatePanel和FileSelectPopup等都创建了用于显示和丢弃的窗口。这些函数还为每个调用它们的线程创建了隐藏的窗口。在销毁可见的窗口时,这个隐藏的窗口并没有被销毁。除了这些用户界面库函数外,各种其它的LabWindows/CVI库函数和Windows API函数创建了隐藏的背景窗口。为了避免系统的锁定,必须在线程中对使用这两种方法创建的窗口的Windows消息进行处理。

10. 使用线程局部变量

线程局部变量与全局变量相似,可以在任意线程中对它们进行访问。但是,全局变量对于所有线程只保存一个值,而线程局部变量为每个访问的线程保存一个独立的值。当程序中需要同时在多个上下文中进行相同的任务,而其中每个上下文都对应一个独立的线程时,通常需要使用到线程局部变量。例如,你编写了一个并行的测试程序,其中的每个线程处理一个待测单元,那么你可能需要使用线程局部变量来保存每个单元的特定信息(例如序列号)。

Windows API提供了用于创建和访问线程局部变量的机制,但是该机制对每个进程中可用的线程局部变量的数目进行了限定。LabWindows/CVI Utility Library中的线程局部变量函数没有这种限制。下面的代码展示了如何创建和访问一个保存了整数的线程局部变量。

volatile int quit = 0;
volatile int suspend = 0;
int main (int argc, char *argv[])
{
int functionId;
HANDLE threadHandle;
CmtScheduleThreadPoolFunction (DEFAULT_THREAD_POOL_HANDLE, ThreadFunction, NULL, &functionId);
. . .
// This would typically be done in response to user input or a
// change in program state.
suspend = 1;
. . .
CmtGetThreadPoolFunctionAttribute (DEFAULT_THREAD_POOL_HANDLE, functionId, ATTR_TP_FUNCTION_THREAD_HANDLE, &threadHandle);
ResumeThread (threadHandle);
. . .
return 0;
}
int CVICALLBACK ThreadFunction (void *functionData)
{
while (!quit) {
if (suspend) {
SuspendThread (GetCurrentThread ());
suspend = 0;
}
. . .
}
return 0;
}

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top