任务:在之前的框架上编写 使用按键和触摸屏 的代码(线程方式)
参考文件夹里的 Unix_Linux_Windows_OpenMP多线程编程.pdf P18
1、主线程与子线程的实现流程
当有数据时,内核去唤醒子线程,子线程唤醒主线程。
框架:
/* input_manager.c */
int AllInputDevicesInit(void)
{
/* 调用DeviceInit后,创建子线程 */
}
int GetInputEvent(PT_InputEvent ptInputEvent)
{
/* 休眠 */
/* 被唤醒后,返回数据 */
}
2、在Input_manager.h里
修改 结构体InputOpr, 添加线程id
typedef struct InputOpr
{
char* name;
pthread_t tThreadID;
int (*DeviceInit)(void);
int (*DeviceExit)(void);
int (*GetInputEvent)(PT_InputEvent ptInputEvent);
struct InputOpr* ptNext;
}T_InputOpr, *PT_InputOpr;
3、在input_manager.c 里
static pthread_mutex_t g_tMutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t g_tConVar = PTHREAD_COND_INITIALIZER;
static void *InputEventTreadFunction(void *pVoid)
{
T_InputEvent tInputEvent;
/* 定义函数指针 */
int (*GetInputEvent)(PT_InputEvent ptInputEvent);
GetInputEvent = (int (*)(PT_InputEvent))pVoid;
while (1)
{
if(0 == GetInputEvent(&tInputEvent))
{
/* 唤醒主线程, 把tInputEvent的值赋给一个全局变量 */
/* 访问临界资源前,先获得互斥量 */
pthread_mutex_lock(&g_tMutex);
g_tInputEvent = tInputEvent;
/* 唤醒主线程 */
pthread_cond_signal(&g_tConVar);
/* 释放互斥量 */
pthread_mutex_unlock(&g_tMutex);
}
}
return NULL;
}
int AllInputDevicesInit(void)
{
PT_InputOpr ptTmp = g_ptInputOprHead;
int iError = -1;
while (ptTmp)
{
if (0 == ptTmp->DeviceInit())
{
/* 创建子线程 */
pthread_create(&ptTmp->tTreadID, NULL, InputEventTreadFunction, ptTmp->GetInputEvent);
iError = 0;
}
ptTmp = ptTmp->ptNext;
}
return iError;
}
int GetInputEvent(PT_InputEvent ptInputEvent)
{
/* 休眠 */
pthread_mutex_lock(&g_tMutex);
pthread_cond_wait(&g_tConVar, &g_tMutex);
/* 被唤醒后,返回数据 */
*ptInputEvent = g_tInputEvent;
pthread_mutex_unlock(&g_tMutex);
return 0;
}
之前轮询方式和select方式,都是以非阻塞方式,现在改成阻塞方式
4、在stdin.c里
static int StdinGetInputEvent(PT_InputEvent ptInputEvent)
{
/* 如果有数据就读取、处理、返回
* 如果没有数据, 立刻返回, 不等待
*/
/* select, poll 可以参数 UNIX环境高级编程 */
char c;
/* 处理数据 */
ptInputEvent->iType = INPUT_TYPE_STDIN;
c = fgetc(stdin); /* 一直休眠,直到有数据输入 */
gettimeofday(&ptInputEvent->tTime, NULL);
if (c == 'u')
{
ptInputEvent->iVal = INPUT_VALUE_UP;
}
else if (c == 'n')
{
ptInputEvent->iVal = INPUT_VALUE_DOWN;
}
else if (c == 'q')
{
ptInputEvent->iVal = INPUT_VALUE_EXIT;
}
else
{
ptInputEvent->iVal = INPUT_VALUE_UNKNOWN;
}
return 0;
}
5、在touchscreen.c里
4.1、修改TouchScreenDevInit():
g_tTSDev = ts_open(pcTSName, 0); /* 以阻塞方式打开 */
/* 注意: 由于要用到LCD的分辨率, 此函数要在SelectAndInitDisplay之后调用 */
static int TouchScreenDevInit(void)
{
char *pcTSName = NULL;
if ((pcTSName = getenv("TSLIB_TSDEVICE")) != NULL )
{
g_tTSDev = ts_open(pcTSName, 0); /* 以阻塞方式打开 */
}
else
{
g_tTSDev = ts_open("/dev/event0", 1);
}
if (!g_tTSDev) {
DBG_PRINTF("ts_open error!\n");
return -1;
}
if (ts_config(g_tTSDev)) {
DBG_PRINTF("ts_config error!\n");
return -1;
}
if (GetDispResolution(&giXres, &giYres))
{
return -1;
}
return 0;
}