Labwindows/cvi是一款强大的上位机设计软件。其大致设计思路为根据各个控件对应的回调函数来完成特定的任务,但是由于各个回调函数都在一个线程里进行响应,这就意味着当一个回调函数在进行的时候,其他回调函数是无法响应的。为了解决这个问题就要避免在回调函数中进行复杂的,耗时的操作。可以通过在回调函数中开辟新线程的方式避免控件响应迟缓的问题。
由于面板上的资源是共用的,因此如果回调函数开辟的线程都要用到共同的某个公共资源,此时就可能出现资源冲突造成错误的读写操作。为了避免公共资源冲突的现象可以采用锁操作来进行规避。只有一个线程获得到锁之后才能开始线程,在该线程工作的过程中如果有和它冲突的线程被建立,就必须等第一个线程完成后归还它获得到的锁,第二个线程才能开始工作。这里的锁就向接力赛中的接力棒,只有拿到棒的人才能开始跑。
本文将通过一个简单的打印字符工程来延时如何开辟线线程和利用锁操作来避免公共资源的访问冲突。
1.面板设置
本工程实现以下目标:
1.点击开启线程1时创建一个新的线程,在该线程中完成,每秒打印一次 1:hello world 总共打印5次
2.点击开启线程2时创建一个新的线程,在该线程中完成,每秒打印一次 2: hello world 总共打印5次
3.点击清空信息时,清空信息框中的信息。
4.在进行上述操作时,各个按钮需要及时响应。
根据上述要求创建以下面板界面:
2.整体代码
#include <ansi_c.h>
#include <utility.h>
#include <cvirte.h>
#include <userint.h>
#include "test4.h"
static int panelHandle;
static int threadid1,threadid2;
static void *functiondata="";
static CmtThreadLockHandle LOCK;
int main (int argc, char *argv[])
{
if (InitCVIRTE (0, argv, 0) == 0)
return -1; /* out of memory */
if ((panelHandle = LoadPanel (0, "test4.uir", PANEL)) < 0)
return -1;
CmtNewLock("",0,&LOCK); //创建新锁
DisplayPanel (panelHandle);
RunUserInterface ();
CmtDiscardLock(LOCK); //销毁锁
DiscardPanel (panelHandle);
return 0;
}
int CVICALLBACK p_exit (int panel, int event, void *callbackData,
int eventData1, int eventData2)
{
switch (event)
{
case EVENT_GOT_FOCUS:
break;
case EVENT_LOST_FOCUS:
break;
case EVENT_CLOSE:
QuitUserInterface (0);
break;
}
return 0;
}
int CVICALLBACK threadfunction1(void *functiondata)
{
CmtGetLock(LOCK); //获得锁
char i=0;
while (i<5)
{
SetCtrlVal (panelHandle, PANEL_TEXTBOX,"1:hello world\n" );
Delay(1);
i++;
}
CmtReleaseLock (LOCK); //消除锁
CmtReleaseThreadPoolFunctionID (DEFAULT_THREAD_POOL_HANDLE,threadid1); //清除线程
return 0;
}
int CVICALLBACK text1 (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
switch (event)
{
case EVENT_COMMIT:
CmtScheduleThreadPoolFunction(DEFAULT_THREAD_POOL_HANDLE,threadfunction1,functiondata,&threadid1);//创建新线程
SetCtrlVal (panelHandle, PANEL_TEXTBOX,"线程1已创建\n" );
break;
}
return 0;
}
int CVICALLBACK threadfunction2(void *functiondata)
{
CmtGetLock(LOCK); //获得锁
char i=0;
while (i<5)
{
SetCtrlVal (panelHandle, PANEL_TEXTBOX,"2:hello world\n" );
Delay(1);
i++;
}
CmtReleaseLock (LOCK); //消除锁
CmtReleaseThreadPoolFunctionID (DEFAULT_THREAD_POOL_HANDLE,threadid2); //清除线程
return 0;
}
int CVICALLBACK text2 (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
switch (event)
{
case EVENT_COMMIT:
CmtScheduleThreadPoolFunction(DEFAULT_THREAD_POOL_HANDLE,threadfunction2,functiondata,&threadid2);//创建新线程
SetCtrlVal (panelHandle, PANEL_TEXTBOX,"线程2已创建\n" );
break;
}
return 0;
}
int CVICALLBACK clr (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
switch (event)
{
case EVENT_COMMIT:
DeleteTextBoxLines (panelHandle, PANEL_TEXTBOX,0,-1); //清空textbox
break;
}
return 0;
}
3.调试
工程文件已上传至【免费】labwindows/CVI线程锁的基本使用方法资源-CSDN文库
有线程锁的效果:
无线程锁的效果: