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

LabWindows?/CVI中的多线程技术

时间:12-23 来源:互联网 点击:
检测对GetPointerToVarName的不匹配调用

可以通过DefineThreadSafeScalarVar和DefineThreadSafeArrayVar的最后一个参数(maxGetPointerNestingLevel),来指定最大数目的嵌套调用。通常可以把这个参数设为0,这样GetPointerToVarName在检测到同一线程中对GetPointerToVarName的两次连续调用而中间没有对ReleasePointerToVarName进行调用时,就会报出一个运行错误。例如,下面的代码在第二次执行的时候会报出run-time error的错误,因为它忘记了调用ReleasePointerToCount函数。

int IncrementCount (void)
{
int *countPtr;

countPtr = GetPointerToCount(); /* run-time error on second execution */
(*countPtr)++;
/* Missing call to ReleasePointerToCount here */
return 0;
}

如果代码中必须对GetPointerToVarName进行嵌套调用时,那么可将maxGetPointerNestingLevel参数设为一个大于零的整数。例如,下面的代码将maxGetPointerNestingLevel参数设定为1,因此它允许对GetPointerToVarName进行一级嵌套调用。

DefineThreadSafeScalarVar (int, Count, 1);
int Count (void)
{
int *countPtr;
countPtr = GetPointerToCount();
(*countPtr)++;
DoSomethingElse(); /* calls GetPointerToCount */
ReleasePointerToCount ();
return 0;
}
void DoSomethingElse(void)
{
int *countPtr;
countPtr = GetPointerToCount(); /* nested call to GetPointerToCount */
... /* do something with countPtr */
ReleasePointerToCount ();
}

如果不知道GetPointerToVarName的最大嵌套级别,那么请传递TSV_ALLOW_UNLIMITED_NESTING来禁用对GetPointerToVarName函数的不匹配调用检查。

线程安全队列

使用LabWindows/CVI Utility Library的线程安全队列,可以在线程间安全地传递数据。当需要用一个线程来采集数据而用另一个线程来处理数据时,这种技术非常有用。线程安全队列在其内部处理所有的数据锁定。通常说来,应用程序中的辅助线程获取数据,而主线程在数据可用时读取数据然后分析并/或显示数据。下面的代码显示了线程如何使用线程安全队列将数据传递到另外一个线程。在数据可用时,主线程利用回调函数来读取数据。

int queue;
int panelHandle;

int main (int argc, char *argv[])
{
if (InitCVIRTE (0, argv, 0) == 0)
return -1; /* out of memory */
if ((panelHandle = LoadPanel(0, "DAQDisplay.uir", PANEL)) < 0)
return -1;
/* create queue that holds 1000 doubles and grows if needed */
CmtNewTSQ(1000, sizeof(double), OPT_TSQ_DYNAMIC_SIZE, &queue);
CmtInstallTSQCallback (queue, EVENT_TSQ_ITEMS_IN_QUEUE, 500, QueueReadCallback, 0, CmtGetCurrentThreadID(), NULL);
CmtScheduleThreadPoolFunction (DEFAULT_THREAD_POOL_HANDLE, DataAcqThreadFunction, NULL, NULL);
DisplayPanel (panelHandle);
RunUserInterface();
. . .
return 0;
}
void CVICALLBACK QueueReadCallback (int queueHandle, unsigned int event, int value, void *callbackData)
{
double data[500];
CmtReadTSQData (queue, data, 500, TSQ_INFINITE_TIMEOUT, 0);
}

6. 避免死锁

当两个线程同时等待对方持有的线程锁定对象时,代码就不能继续运行了。这种状况被称为死锁。如果用户界面线程发生死锁,那么它就不能响应用户的输入。用户必须非正常地结束程序。下面的例子解释了死锁是如何发生的。

线程1:调用函数来获取线程锁A(线程1:无线程锁,线程2:无线程锁)。

线程1:从获取线程锁的函数返回(线程1:持有线程锁A,线程2:无线程锁)。

切换到线程2:(线程1:持有线程锁A,线程2:无线程锁)。

线程2:调用函数来获取线程锁B(线程1:持有线程锁A,线程2:无线程锁)。

线程2:从获取线程锁的函数返回(线程1:持有线程锁A,线程2:持有线程锁B)。

线程2:调用函数来获取线程锁A(线程1:持有线程锁A,线程2:持有线程锁B)。

线程2:由于线程1持有线程锁A而被阻塞(线程1:持有线程锁A,线程2:持有线程锁B)。

切换到线程1:调用函数来获取线程锁B(线程1:持有线程锁A,线程2:持有线程锁B)。

线程1:调用函数来获取线程锁B(线程1:持有线程锁A,线程2:持有线程锁B)。

线程1:由于线程2持有线程锁A而被阻塞(线程1:持有线程锁A,线程2:持有线程锁B)。

与不对数据进行保护时产生的错误相似,由于程序运行的情况不同导致线程切换的时序不同,死锁错误间歇性地发生。例如,如果直到线程1持有线程锁A和B后才切换到线程2,那么线程1就可以完成工作而

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

网站地图

Top