采用select的方式实现多输入

在上一篇博客中,我才用了轮询的方法实现LCD文本的多输入控制。主程序如下:

while (1)
	{
		if (0 == GetInputEvent(&tInputEvent))
		{
			if (tInputEvent.iVal == INPUT_VAL_DOWN)
			{
				ShowNextPage();
			}
			else if (tInputEvent.iVal == INPUT_VAL_UP)
			{
				ShowPrePage();			
			}
			else if (tInputEvent.iVal == INPUT_VAL_EXIT)
			{
				return 0;
			}
		}
	}

这样的做的明显缺陷是:

  • cpu一直在等待查询的结果。导致CPU的占用率非常高。在实际的工程中这是不可接受的。
    因此,我们采用了select和poll机制。
select机制:

参考:UNIX环境高级编程 I/O多路转接

监测多个文件,只要有某一个文件可读/可写/异常或超时,即返回

int select(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,struct timeval *timeout);

nfds:最大文件句柄+1
readfds:监视这些文件描述符的读变化,即在这个集合中是否有我们关心的文件描述符可读了。
writefds:被监测是否可写的文件,同上。
exceptfds:被监测是否有异常的文件,同上。
timeout:超时时间。当写为0的时候表示查询:不管有没有变化都返回。当写为NULL的时候表示:无论等多长时间,知道我关心的这些集合中有文件描述符发生了期望的变化。
返回值:当有文件描述符发生了期望的变化,返回变化的数量。

为什么select可以降低CPU的占用率?因为select的监测是休眠监测。
程序修改
  • select函数中,需要提供被监测是否有异常的文件,这就要两个输入设备提供其句柄。
    因此,要在应用程序底层获取设备句柄。
static int TSDevInit(void)
{
	char *pcTsdevice=NULL;  

    if((pcTsdevice=getenv("TSLIB_TSDEVICE"))!= NULL)/*在环境链表中寻找变量名为TSLIB_TSDEVICE的设备*/
	{
    	g_ptTsDev = ts_open(pcTsdevice,1);/*非拥塞的打开*/
    }
	else/*环境链表中,TSLIB_TSDEVICE未注册*/
	{
    	g_ptTsDev = ts_open("/dev/input/event0", 1);/*则以键盘作为输入*/
    }

	if (!g_ptTsDev) {
		printf("TS_open error\n");
		return -1;
	}

	if (ts_config(g_ptTsDev)) {
		printf("ts_config error\n");
		return -1;
	}
	
	if (GetDispResolution(&g_iXres, &g_iYres))/*获取显示屏的分辨率*/
	{
		return -1;
	}
	/*分辨率由FBDeviceInit函数从底层获取,因此触摸屏需要在fb(lcd)初始化之后再初始化*/

	g_tTSDevInptOpr.iFd=ts_fd(g_ptTsDev);/*获取句柄*/
	
	return 0;
}
  • 在input_manager.h中,对fd_set进行初始化。
typedef struct InputOpr {
	unsigned int iFd;
	unsigned char* name;
	int (*InputDevInit)(void);
	int (*InputDevExit)(void);
	int (*InputDevEventIdel)(PT_InputEventOpr pt_InputEventOpr);
	struct InputOpr *ptNext;
}T_InputOpr,*PT_InputOpr;
  • 在事件处理函数GetInputEvent中,调用select函数;当select函数被调用,随即进入休眠状态,当有事件发生的时候,select将发生事件的fd返回。而之前的程序中,需要在主程序中循环调用GetInputEvent函数,在GetInputEvent需要不断的查询当前设备的状态。
    初始化函数:
int AllInputDevicesInit(void)
{
	PT_InputOpr ptTemp = g_ptInputOprHead;
	g_iMaxFd=0;

	FD_ZERO(&g_tRfds);

	while(ptTemp)
	{
		if(0 == ptTemp->InputDevInit())/*调用成功*/
		{
			FD_SET(ptTemp->iFd, &g_tRfds);
			
			if(ptTemp->iFd > g_iMaxFd)
				g_iMaxFd=ptTemp->iFd;
			
			ptTemp = ptTemp->ptNext;
		}
		else
			return -1;
	}
	return 0;
}

事件处理函数:

int GetInputEvent(PT_InputEventOpr ptInputEvent)/*事件处理,或者叫事件查询*/
{
	PT_InputOpr ptTemp = g_ptInputOprHead;
	int retval;

	/*有事件再返回,超时系数设置为0*/
	retval=select(g_iMaxFd+1,&g_tRfds,NULL,NULL,NULL);

	/*事件发生返回后查询是哪个事件发生了*/
	if(retval)
	{
		while(ptTemp)
		{
		    /*事件发生,结构体中相应的位置位*/	
			if(FD_ISSET(ptTemp->iFd,&g_tRfds))				
			{
				ptTemp->InputDevEventIdel(ptInputEvent);
				return 0;
			}
			ptTemp = ptTemp->ptNext;/*没有发生该事件随即查询链表中另一个事件*/
		}
	}
	return -1;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值