您的位置:首页 > 其它

系统软件性能调优策略(一)——通过有名管道FIFO来检测消息队列中是否可读

2010-04-19 14:04 260 查看
在基于网络的开发中,socket的发送、接收状态,可以通过select来进行检测。但如果又有其他的业务要处理,比如处理消息队列,则可能会出现两难的情况:
1)tmval.tv_usec = 20;
select(sockid,,,,&tmval);
select等待指定时间,如果期间有消息需要处理,则会造成CPU资源的浪费、业务流程处理的延时,而产生性能降低;
2)select(sockid,,,,0)
NO_WAIT方式,则可能会造成系统空转,CPU无谓负荷高,造成系统资源的浪费。

一种好的处理方式是,借用复用I/O的技术,将队列的读取转换为有名管道FIFO的状态检测,具体如下:

一、有名管道的准备:
A)创建有名管道
#define MY_FIFO_NAME	"myfifo"
fp = mkfifo(FifoFile, mode);
B)向队列中写入消息的同时,向该管道内写入1个字符
fifoout = open(FifoFile, O_RDWR | O_NONBLOCK);
#ifndef WIN32
do{
/* 每次向队列中写入消息时,也向FIFO管道中写入一个字符 */
fifoRet = write(fifoout, "T", 1);
if(fifoRet <= 0){
/* 屏蔽中断信号 */
if (errno==EAGAIN || errno==EWOULDBLOCK || errno==EINTR)
continue;
else{
return(-1);
}
}
else
break;
}while(1);

close(fifoout);
#endif

C)在读取消息队列后,也读取FIFO中的一个字符
#ifndef WIN32
do{
fifoRet = read(fifoout, fifoStr,1);
if(fifoRet<=0){
/* 屏蔽中断信号 */
if (errno==EAGAIN || errno==EWOULDBLOCK || errno==EINTR)
continue;
else{
fprintf(stderr,"read fifo fail, fifoout=%d, syserr=%d/n", fifoRet, errno);
break;
}
}
else
break;
}while(1);
#endif
D)系统退出时,删除管道FIFO
fifoRet = unlink(FifoFile);

二、有名管道的的I/O复用
A)将有名管道的描述符添加到readfds中
#ifndef WIN32
/* 将有名管道myfifo的fd追加到readfds中,以进行select */
FD_SET(fifoout, &readfds);
#endif
B)进行select,并对结果进行判断
tmval.tv_sec = 0;
tmval.tv_usec = 30;		/* miniseconds, 30毫秒*/
ret = select(FD_SETSIZE,&readfds,&writefds,
(fd_set *)0, (struct timeval *)&tmval);
/* 只有fifo可读时,才进行网路发送 */
if(ret >0 && FD_ISSET(fifoout,&readfds))
msgrcv(...);


这样,即使是在以下任何一种情况下,都会使得select被激活并返回,就不会造成CPU资源的效率,并且系统的性能将大大得到提高。

备注:
此法,只适用于Unix。由于Windows上的select仅仅对socket有效,所以此法不适用。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: