在【1.7 数码相册—电子书(3)—轮询方式支持多输入】和【1.7 数码相册—电子书(4)—select支持多输入】中,我们采用了轮询方式支持多输入,并且采用select函数改进了轮询方式的CPU占用率过高的问题。 在这篇博客中,采用多线程的方式,来改进了轮询方式的CPU占用率过高的问题,同时修改touchscreen.c支持滑动翻页,分为如下三个线程:
主线程:负责初始化各种设备,创建子线程,并协调它们进行显示电子书的效果,等待子线程的输入信息,处于休眠。stdin输入子线程:负责响应stdin输入设备的输入事件的子线程,当发生输入事件时,主线程处于休眠状态,执行此线程的任务,执行完毕后则重新唤醒主线程。touchscreen输入子线程:负责响应touchscreen输入设备的输入事件的子线程,当发生输入事件时,主线程处于休眠状态,执行此线程的任务,执行完毕后则重新唤醒主线程。并且两个子线程同一时间能只能执行一个。
此函数是在main.c中被调用,初始化所有输入设备的时候创建对应子线程。
/* 初始化所有支持的Input设备 */ int AllInputDeviceInit() { int error; PT_InputOpr ptTmp; error = -1; ptTmp = s_ptInputOprHead; while (ptTmp) { if (ptTmp->DeviceInit() == 0) { /* 创建子线程 */ error = pthread_create(&ptTmp->threadId, NULL, InputEventThreadFunction, ptTmp->GetInputEvent); if (error != 0) { printf("pthread_creat error ,error code : %d\n", error); return error; } } ptTmp = ptTmp->ptNext; } return 0; }此函数在发生对应子线程的时候被执行。
/* 输入事件线程函数 */ static void *InputEventThreadFunction(void *pvoid) { T_InputEvent tmpInputEvent; /* 定义函数指针 */ int (*GetInputEvent)(PT_InputEvent ptInputEvent); GetInputEvent = (int (*)(PT_InputEvent))pvoid; while(1) { /* 调用函数获得输入事件 */ if (GetInputEvent(&tmpInputEvent) == 0) { /* 唤醒主线程,把tmpInputEvent的值赋给一个全局变量 */ /* 访问临界资源前,先获得互斥量 */ pthread_mutex_lock(&s_tMutex); //加锁 s_tInputEvent = tmpInputEvent; /* 唤醒主线程 */ pthread_cond_signal(&s_tCondvar); //发送信号给处于阻塞等待状态的主线程 /* 释放互斥量 */ pthread_mutex_unlock(&s_tMutex); //解锁 } } return NULL; }此函数在发生对应子线程的时候被执行,通过1.2中的函数的GetInputEvent(&tmpInputEvent),被调用。
/* 获取输入事件 */ int GetInputEvent(PT_InputEvent ptInputEvent) { /* 休眠 */ /* 进入临界资源前,获得互斥量 */ pthread_mutex_lock(&s_tMutex); /* pthread_cond_wait会先解除之前的pthread_mutex_lock锁定的s_tMutex, * 然后阻塞在等待队列里休眠,直到再次被唤醒 * (大多数情况下是等待的条件成立而被唤醒,唤醒后,该进程会先锁定pthread_mutex_lock(&s_tMutex) */ pthread_cond_wait(&s_tCondvar, &s_tMutex); /* 被唤醒之后(执行完子线程对应的InputEventThreadFunction()函数)返回数据 */ *ptInputEvent = s_tInputEvent; /* 释放互斥量 */ pthread_mutex_unlock(&s_tMutex); //解锁 return 0; }通过调用tslib库:
获取触摸屏滑动按下的第一个点startPressured和松开最后一个点endReleased;计算二者的x坐标的差值,delta = endReleased.x - startPressured.x,标准为滑动距离为触摸屏x分辨率的1/5;若delta > s_Xres / 3滑动,往右滑,则翻到上一页;若delta < (0 - s_Xres / 3),往左滑,则翻到下一页; /** * @Description: 采用查询的方式获读取touchscreen数据 * @param ptInputEvent - 表示input设备的结构体. * @return 有数据:0 无数据:-1 */ static int TouchScreenGetInputEvent(PT_InputEvent ptInputEvent) { int ret; int delta; int startflag; int endflag; struct ts_sample samp; struct ts_sample startPressured; struct ts_sample endReleased; endflag = startflag = 0; while(1) { /* 如果无数据则休眠 */ ret = ts_read(s_pTSDev, &samp, 1); if (ret == 1) { /* 第一次按下 */ if ((samp.pressure > 0) && (startflag == 0)) { /* 记录数据 */ startPressured = samp; startflag = 1; } /* 最后松开 */ if (samp.pressure <= 0) { endReleased = samp; endflag = 1; } /* 松开处理数据 */ if (!startflag && endflag == 1) return -1; //异常情况 else if((startflag == 1) && (endflag == 1)) { delta = endReleased.x - startPressured.x; //计算差值 ptInputEvent->time = endReleased.tv; ptInputEvent->type = INPUT_TYPE_TOUCHSCREEN; if (delta > s_Xres / 3) ptInputEvent->val = INPUT_VALUE_UP; //上翻 else if(delta < (0 - s_Xres / 3)) ptInputEvent->val = INPUT_VALUE_DOWN; //下翻 else ptInputEvent->val = INPUT_VALUE_UNKONW; //未知 return 0; } } else return -1; } return 0; }执行make,得到可执行文件show_file
由于使用到触摸屏,需要调用tslib库来进行校准
执行./show_file -l,显示出当前支持的设备 执行./shoe_file -s 16 -h HZK16 -f ./MSYH.TTF hz.txt 执行ps -T,可以看到此时的三个线程: 在没有任何外部输入的时候,CPU占用率为0,处于休眠 有输入时,才唤醒程序,同时也支持滑动(在这里展示不了)。