linux应用程序_1_文本浏览器_8_输入设备_4_多线程机制
上一篇引入了select机制,解决了Cpu占用率高的问题,但它只适用于简单场合,为了提高灵活性,本文引入多线程
基本思路:所有线程平时处于休眠状态,当某个输入设备有数据可读,唤醒该输入设备的线程,处理数据,再由该线程唤醒主线程,呈递数据给main
所有的线程共同全局变量,为了避免干扰,线程机制中有一个互斥锁,每次使用全局变量之前,都应该先获得互斥锁,使用完后释放互斥锁,以达到多个线程无法同时操作同一个变量
在轮询机制的代码基础上修改
在input_manager.h
添加头文件
#include <pthread.h>
为输入结构体添加进程号成员
typedef struct InputOpr{
char *pcName;
pthread_t tId;
int (*InputInit)(void);
int (*InputExit)(void);
int (*InputGetEvent)(PT_InputEventOpr ptInputEventOpr);
struct InputOpr *ptNext;
}T_InputOpr, *PT_InputOpr;
在input_manager.c
添加头文件
#include <pthread.h>
修改输入设备初始化接口,在其中为每个输入设备创建线程
int ReallyInputInit(void)
{
int iError = 1;
PT_InputOpr ptTmp = g_ptInputOpr;
while(ptTmp)
{
if(ptTmp->InputInit)
iError &= ptTmp->InputInit();
pthread_create(&ptTmp->tId, NULL, &ThreadFunction, ptTmp);
ptTmp = ptTmp->ptNext;
}
return iError;
}
文件头部定义互斥锁和条件变量
pthread_mutex_t g_tMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t g_tCondvar = PTHREAD_COND_INITIALIZER;
修改获取事件接口:作为主线程等待子线程接收到数据来唤醒
int GetInputEvent(PT_InputEventOpr ptInputEventOpr)
{
pthread_mutex_lock(&g_tMutex);
printf(" 1 GetInputEvent\r\n");
pthread_cond_wait(&g_tCondvar, &g_tMutex);
printf(" 2 GetInputEvent\r\n");
*ptInputEventOpr = g_tInputEvent;
pthread_mutex_unlock(&g_tMutex);
return 0;
}
添加子线程处理函数:
若有数据返回,则唤醒主进程
void *ThreadFunction(void *pVoid)
{
PT_InputOpr ptTmp = (PT_InputOpr) pVoid;
T_InputEventOpr tEventTmp;
while(1)
{
printf("%s\r\n", ptTmp->pcName);
if(!ptTmp->InputGetEvent(&tEventTmp))
{
printf("A\r\n");
pthread_mutex_lock(&g_tMutex);
g_tInputEvent = tEventTmp;
pthread_cond_signal(&g_tCondvar);
pthread_mutex_unlock(&g_tMutex);
}
}
return NULL;
}
在stdin.c中
获取事件时以阻塞方式读取,没有数据则休眠
static int StdinInputGetEvent(PT_InputEventOpr ptInputEventOpr)
{
char cOneChar;
ptInputEventOpr->iVal = INPUT_TYPE_STDIN;
cOneChar = fgetc(stdin);
switch(cOneChar)
{
case 'n':
{
ptInputEventOpr->iVal = INPUT_VAL_NEXT;
break;
}
case 'p':
{
ptInputEventOpr->iVal = INPUT_VAL_PRE;
break;
}
case 'q':
{
ptInputEventOpr->iVal = INPUT_VAL_EXIT;
break;
}
default:
ptInputEventOpr->iVal = INPUT_VAL_UNKNOWN;
}
return 0;
}
在ts.c中
同样以阻塞方式打开设备,没有数据时休眠
static int TsInputGetEvent(PT_InputEventOpr ptInputEventOpr)
{
struct ts_sample tSamp;
int iRet;
static struct timeval tPreTime;
iRet = ts_read(g_ptTs, &tSamp, 1);
if (iRet < 0)
return -1;
iRet = IsOutOf500ms(&tPreTime, &tSamp.tv);
if(!iRet)
return -1;
tPreTime.tv_sec = tSamp.tv.tv_sec;
tPreTime.tv_usec = tSamp.tv.tv_usec;
ptInputEventOpr->iType = INPUT_TYPE_TS;
if(tSamp.x < (g_iXres / 3))
ptInputEventOpr->iVal = INPUT_VAL_PRE;
else if(tSamp.x > (g_iXres * 2 / 3))
ptInputEventOpr->iVal = INPUT_VAL_NEXT;
else
ptInputEventOpr->iVal = INPUT_VAL_EXIT;
return 0;
}