第三阶段应用层——1.7 数码相册—电子书(5)—多线程支持多输入

数码相册——电子书多线程支持多输入

  • 硬件平台:韦东山嵌入式Linxu开发板(S3C2440.v3)
  • 软件平台:运行于VMware Workstation 12 Player下UbuntuLTS16.04_x64 系统
  • 参考资料:《嵌入式Linux应用开发手册》、《嵌入式Linux应用开发手册第2版》、【多线程编写】
  • 开发环境:Linux 3.4.2内核、arm-linux-gcc 4.3.2工具链
  • 源码仓库:https://gitee.com/d_1254436976/Embedded-Linux-Phase-3


一、前言

【1.7 数码相册—电子书(3)—轮询方式支持多输入】【1.7 数码相册—电子书(4)—select支持多输入】中,我们采用了轮询方式支持多输入,并且采用select函数进了轮询方式的CPU占用率过高的问题。
在这篇博客中,采用多线程的方式,来改进了轮询方式的CPU占用率过高的问题,同时修改touchscreen.c支持滑动翻页,分为如下三个线程

  1. 主线程:负责初始化各种设备创建子线程,并协调它们进行显示电子书的效果等待子线程的输入信息,处于休眠
  2. stdin输入子线程:负责响应stdin输入设备的输入事件的子线程,当发生输入事件时,主线程处于休眠状态执行此线程的任务,执行完毕后则重新唤醒主线程
  3. touchscreen输入子线程:负责响应touchscreen输入设备的输入事件的子线程,当发生输入事件时,主线程处于休眠状态执行此线程的任务,执行完毕后则重新唤醒主线程

并且两个子线程同一时间能只能执行一个

二、修改代码

1、修改管理者input_manager.c文件

1.1 创建线程

此函数是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;
}

1.2 输入事件线程函数

此函数在发生对应子线程的时候被执行。

/* 输入事件线程函数 */
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.3 获取输入事件的函数

此函数在发生对应子线程的时候被执行,通过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;
}

2、修改touchscreen.c设备文件,支持滑动翻页

通过调用tslib库:

  1. 获取触摸屏滑动按下的第一个点startPressured和松开最后一个点endReleased
  2. 计算二者的x坐标的差值delta = endReleased.x - startPressured.x标准为滑动距离为触摸屏x分辨率的1/5
  3. delta > s_Xres / 3滑动,往右滑,则翻到上一页
  4. 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;
}

三、编译与烧写

1、编译

执行make,得到可执行文件show_file

2、运行

由于使用到触摸屏,需要调用tslib库来进行校准

  1. 执行./show_file -l,显示出当前支持的设备
    在这里插入图片描述
  2. 执行./shoe_file -s 16 -h HZK16 -f ./MSYH.TTF hz.txt
    执行ps -T,可以看到此时的三个线程:
    在这里插入图片描述
    没有任何外部输入的时候,CPU占用率为0,处于休眠
    输入时才唤醒程序同时也支持滑动(在这里展示不了)。
    在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_42813232/article/details/107089644