免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5654 | 回复: 5
打印 上一主题 下一主题

[Linux] 使用select实现消息队列超时 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-09-25 18:05 |只看该作者 |倒序浏览
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. #include <sys/ipc.h>
  6. #include <sys/stat.h>
  7. #include <sys/msg.h>
  8. #include <errno.h>

  9. #define BUFFER 255
  10. #define PERM S_IRUSR | S_IWUSR

  11. struct msgtype
  12. {
  13.     long mtype;
  14.     char buffer[BUFFER+1];
  15. };

  16. void recv(int msgid)
  17. {
  18.     while(1)
  19.     {
  20.     int fd[2];
  21.     pid_t pid;
  22.     if(pipe(fd) < 0)
  23.     {
  24.         fprintf(stderr,"pipe error!\n");
  25.         exit(-1);
  26.     }

  27.     if((pid = fork()) == 0)
  28.     {
  29.         close(fd[0]);
  30.         int rc;
  31.         struct msgtype msg;
  32.         if((rc = msgrcv(msgid,&msg,sizeof(struct msgtype),0,0)) == -1)
  33.         {
  34.             fprintf(stderr,"msgrcv error!\n");
  35.             exit(-1);
  36.                            }


  37.         rc = write(fd[1],msg.buffer,strlen(msg.buffer));
  38.         if(rc < 0)
  39.         {
  40.             fprintf(stderr,"write error!\n");
  41.             exit(-1);
  42.         }
  43.         exit(0);
  44.     }
  45.     else if(pid > 0)
  46.     {
  47.         char buf[256] = {0};
  48.         fd_set rfds;
  49.         struct timeval tv;
  50.         int rc;
  51.         FD_ZERO(&rfds);
  52.         FD_SET(fd[0],&rfds);
  53.         tv.tv_sec = 3;
  54.         tv.tv_usec = 0;

  55.         rc = select(fd[0]+1,&rfds,NULL,NULL,&tv);
  56.         if(-1 == rc)
  57.         {
  58.             fprintf(stderr,"select error!\n");
  59.             exit(-1);
  60.         }
  61.         else if(rc)
  62.         {
  63.             if(FD_ISSET(fd[0],&rfds))
  64.             {
  65.                 rc = read(fd[0],buf,256);
  66.                 buf[rc] = 0;
  67.                 if(rc == -1)
  68.                 {
  69.                     fprintf(stderr,"read error!\n");
  70.                     exit(-1);
  71.                 }
  72.                       printf("I have receive a message : %s\n",buf);
  73.             }
  74.         }
  75.         else
  76.         {
  77.             printf("no data timeout!\n");
  78.             return ;
  79.         }
  80.     }
  81.     }

  82. }


  83. int main(int argc, char **argv)
  84. {
  85.     if(argc != 2)
  86.     {
  87.         printf("usage ./test string\n");
  88.         exit(-1);
  89.     }

  90.     int msgid = msgget(IPC_PRIVATE, PERM | IPC_CREAT | IPC_EXCL);
  91.     if(msgid == -1)
  92.     {
  93.         fprintf(stderr,"msgget error!\n");
  94.         exit(-1);
  95.     }

  96.     pid_t pid;
  97.     int i;
  98.     for(i = 0; i < 4; i++)
  99.     {
  100.         pid = fork();
  101. if(pid == 0 || pid == -1)
  102.             break;
  103.     }

  104.     if(pid == 0)
  105.     {

  106.         struct msgtype msg;
  107.         msg.mtype = 1;
  108.         strcpy(msg.buffer,argv[1]);

  109.         int rc = msgsnd(msgid,&msg,sizeof(struct msgtype),0);
  110.         if(rc == -1)
  111.         {
  112.             fprintf(stderr,"msgsnd error!\n");
  113.             exit(-1);
  114.         }
  115.         else
  116.         {
  117.             printf("msgsnd success!\n");
  118.         }
  119.     }
  120.     else if(pid > 0)
  121.     {
  122.         pthread_t tid,tid2,tid3,tid4,tid5;

  123.             pthread_create(&tid,NULL,(void*)recv,(void*)msgid);
  124.             pthread_join(tid,NULL);
  125. wait(NULL);
  126.     }
  127.     else
  128.     {
  129.         fprintf(stderr,"fork error!\n");
  130.         exit(-1);
  131.     }

  132.     return 0;

  133. }           
复制代码
以上是我的代码,使用select与管道来实现消息队列超时退出。其中是在子进程中调用msgrcv函数,在这里可能会产生阻塞,现在有个问题,如果msgrcv阻塞了,父进程可以监控到超时,那么父进程中就退出了,那么子进程会不会退出呢?我不了解select是让谁退出了呢?

论坛徽章:
4
白羊座
日期:2013-09-17 21:59:30技术图书徽章
日期:2013-10-12 22:16:03白羊座
日期:2013-10-14 11:01:40双子座
日期:2013-12-17 18:26:39
2 [报告]
发表于 2013-09-26 00:16 |只看该作者
回复 1# Zoelov
父子进程是独立的,父进程退出不会导致子进程退出,子进程退出也不会导致父进程退出


   

论坛徽章:
0
3 [报告]
发表于 2013-09-26 09:32 |只看该作者
那是不是子进程一直阻塞,根本就无法退出?回复 2# 井蛙夏虫


   

论坛徽章:
4
白羊座
日期:2013-09-17 21:59:30技术图书徽章
日期:2013-10-12 22:16:03白羊座
日期:2013-10-14 11:01:40双子座
日期:2013-12-17 18:26:39
4 [报告]
发表于 2013-09-26 13:49 |只看该作者
回复 3# Zoelov
应当是的


   

论坛徽章:
0
5 [报告]
发表于 2013-09-26 23:00 |只看该作者
slecet()一般就是用来避免使用多进程或者多进程的,select是通过轮询的方式来监听(暂且这么说吧),所以可以取代多进程,一般用于单进程中,进程结束时,

它也就自然结束了。再说,你调用select时的第一个参数,应当是进程中,最大的文件描述符+1,你确定你的fd【0】是当前进程中最大的描述符么?

调用select()时随着需要监听的描述符越多,它的效率就会下降(因为轮询监听),这时如果还是不想使用多进程,就可以用epoll系列函数实现了。

论坛徽章:
0
6 [报告]
发表于 2013-09-26 23:00 |只看该作者
slecet()一般就是用来避免使用多进程或者多进程的,select是通过轮询的方式来监听(暂且这么说吧),所以可以取代多进程,一般用于单进程中,进程结束时,

它也就自然结束了。再说,你调用select时的第一个参数,应当是进程中,最大的文件描述符+1,你确定你的fd【0】是当前进程中最大的描述符么?

调用select()时随着需要监听的描述符越多,它的效率就会下降(因为轮询监听),这时如果还是不想使用多进程,就可以用epoll系列函数实现了。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP