2.使用线程方式获取标准输入

前面讲到,使用非阻塞方式有许多的缺点。主要是单线程,一直占用CPU资源,其他程序无法执行,造成资源的浪费。只能用于较简单循环的场所。而线程灵活,CPU占用率小,适用于大部分场合。

1.条件变量的使用

条件变量是用来通知共享数据的状态信息的机制。由于涉及共享数据,所以一般和互斥量配合使用。

1.1创建和销毁条件变量

pthread_cond_t表示条件变量。在使用pthread_cond_t变量前对其进行初始化。使用默认属性,可以用PTHREAD_COND_INITIALIZER付给变量就可以完成初始化。

pthread_cond_desroy销毁一个条件变量。函数形式为

pthread_cond_desroy(pthread_cond_t * cond)

1.2等待和通知条件变量

条件变量与条件测试是一起调用的。如果测试失败,则调用pthread_cond_wait

int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex)

如果测试成功,则调用pthread_cond_signal函数。

int pthread_cond_signal(pthread_cond_t *cond)
pthread_cond_signal函数只唤醒一个阻塞在cond指向的条件变量上的线程。

2条件变量的应用

2.1 在AllInputDevicesInit函数内创建线程

1 if (0 == ptTmp->DeviceInit())
2 {
3     /* 创建子线程 */
4     pthread_create(&ptTmp->tTreadID, NULL, InputEventTreadFunction, ptTmp->GetInputEvent);            
5     iError = 0;
6 }
7 ptTmp = ptTmp->ptNext;

实现InputEventTreadFunction函数

1 static void *InputEventTreadFunction(void *pVoid)
 2 {
 3     T_InputEvent tInputEvent;
 4     
 5     /* 定义函数指针 */
 6     int (*GetInputEvent)(PT_InputEvent ptInputEvent);
 7     GetInputEvent = (int (*)(PT_InputEvent))pVoid;
 8 
 9     while (1)
10     {
11         if(0 == GetInputEvent(&tInputEvent))
12         {
13             /* 唤醒主线程, 把tInputEvent的值赋给一个全局变量 */
14             /* 访问临界资源前,先获得互斥量 */
15             pthread_mutex_lock(&g_tMutex);
16             g_tInputEvent = tInputEvent;
17 
18             /*  唤醒主线程 */
19             pthread_cond_signal(&g_tConVar);
20 
21             /* 释放互斥量 */
22             pthread_mutex_unlock(&g_tMutex);
23         }
24     }
25 
26     return NULL;
27 }

2.2在Touchscreen.c里全改为阻塞方式

TouchScreenGetInputEvent函数修改如下:

1 static int TouchScreenGetInputEvent(PT_InputEvent ptInputEvent)
 2 {
 3     struct ts_sample tSamp;
 4     struct ts_sample tSampPressed;
 5     struct ts_sample tSampReleased;
 6     int iRet;
 7     int bStart = 0;
 8     int iDelta;
 9 
10     static struct timeval tPreTime;
11     
12 
13     while (1)
14     {
15         iRet = ts_read(g_tTSDev, &tSamp, 1); /* 如果无数据则休眠 */
16         if (iRet == 1)
17         {
18             if ((tSamp.pressure > 0) && (bStart == 0))
19             {
20                 /* 刚按下 */
21                 /* 记录刚开始压下的点 */
22                 tSampPressed = tSamp;
23                 bStart = 1;
24             }
25             
26             if (tSamp.pressure <= 0)
27             {
28                 /* 松开 */
29                 tSampReleased = tSamp;
30 
31                 /* 处理数据 */
32                 if (!bStart)
33                 {
34                     return -1;
35                 }
36                 else
37                 {
38                     iDelta = tSampReleased.x - tSampPressed.x;
39                     ptInputEvent->tTime = tSampReleased.tv;
40                     ptInputEvent->iType = INPUT_TYPE_TOUCHSCREEN;
41                     
42                     if (iDelta > giXres/5)
43                     {
44                         /* 翻到上一页 */
45                         ptInputEvent->iVal = INPUT_VALUE_UP;
46                     }
47                     else if (iDelta < 0 - giXres/5)
48                     {
49                         /* 翻到下一页 */
50                         ptInputEvent->iVal = INPUT_VALUE_DOWN;
51                     }
52                     else
53                     {
54                         ptInputEvent->iVal = INPUT_VALUE_UNKNOWN;
55                     }
56                     return 0;
57                 }
58             }
59         }
60         else
61         {
62             return -1;
63         }
64     }
65 
66     return 0;
67 }

上述程序主要实现:触摸点在x方向上的位移差值超过X分辨率的1/5,就翻页,从而实现滑动翻页。

相关推荐