linux应用程序_1_文本浏览器_8_输入设备_4_多线程机制

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;
}
发布了71 篇原创文章 · 获赞 4 · 访问量 7215

猜你喜欢

转载自blog.csdn.net/floatinglong/article/details/86691877