Chinaunix首页 | 论坛 | 博客
  • 博客访问: 387744
  • 博文数量: 165
  • 博客积分: 436
  • 博客等级: 下士
  • 技术积分: 887
  • 用 户 组: 普通用户
  • 注册时间: 2011-11-10 02:49
文章分类

全部博文(165)

文章存档

2012年(95)

2011年(70)

分类:

2011-12-01 00:23:35

作者:gfree.wind@gmail.com
博客:blog.focus-linux.net   linuxfocus.blog.chinaunix.net
 
 
本文的copyleft归gfree.wind@gmail.com所有,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,注明原作者及原链接,严禁用于任何商业用途。
========================================================

上次的zmq_init看到了启动工作线程,那么今天就开始看看工作线程:
  1. void zmq::select_t::worker_routine (void *arg_)
  2. {
  3.     ((select_t*) arg_)->loop ();
  4. }
封装后的工作线程,就是一直调用select_t的loop。
  1. void zmq::select_t::loop ()
  2. {
  3.     while (!stopping) {

  4.         // Execute any due timers.
  5.         /*
  6.         1. 执行到期的timer;
  7.         2. 如果没有到期的timer,则返回距最近timer的值,保证可以及时执行timer;
  8.         3. 如果没有任何的timer,那么返回0.
  9.         这里,我有两个问题:
  10.         1.如果timeout为0,那么后面的select就没有设置timeout的值。那么除非有事件发生,不然select就不         会返回了。
  11.         2.由于这里的timeout是基于已有的timer计算的。那么当计算完timeout后,插入了新的timer,这个tim
  12.         er的到期时间要小于timeout的值。那么光看这些代码,似乎这个timer不能及时处理啊。
  13.         */
  14.         int timeout = (int) execute_timers ();

  15.         // Intialise the pollsets.
  16.         /*
  17.         需要将描述符复制,不然select会在fset中清除掉没有event的描述符。 
  18.         */
  19.         memcpy (&readfds, &source_set_in, sizeof source_set_in);
  20.         memcpy (&writefds, &source_set_out, sizeof source_set_out);
  21.         memcpy (&exceptfds, &source_set_err, sizeof source_set_err);

         /*
         后面的流程很简单,就是普通的select流程。
         select后,检查描述符,是否可读,可写,或出错。如是的话,则调用相应的处理函数。
         */

  1.         // Wait for events.
  2.         struct timeval tv = {(long) (timeout / 1000),
  3.             (long) (timeout % 1000 * 1000)};
  4.         int rc = select (maxfd + 1, &readfds, &writefds, &exceptfds,
  5.             timeout ? &tv : NULL);

  6. #ifdef ZMQ_HAVE_WINDOWS
  7.         wsa_assert (rc != SOCKET_ERROR);
  8. #else
  9.         if (rc == -1 && errno == EINTR)
  10.             continue;
  11.         errno_assert (rc != -1);
  12. #endif

  13.         // If there are no events (i.e. it's a timeout) there's no point
  14.         // in checking the pollset.
  15.         if (rc == 0)
  16.             continue;

  17.         for (fd_set_t::size_type i = 0; i < fds.size (); i ++) {
  18.             if (fds [i].fd == retired_fd)
  19.                 continue;
  20.             if (FD_ISSET (fds [i].fd, &exceptfds))
  21.                 fds [i].events->in_event ();
  22.             if (fds [i].fd == retired_fd)
  23.                 continue;
  24.             if (FD_ISSET (fds [i].fd, &writefds))
  25.                 fds [i].events->out_event ();
  26.             if (fds [i].fd == retired_fd)
  27.                 continue;
  28.             if (FD_ISSET (fds [i].fd, &readfds))
  29.                 fds [i].events->in_event ();
  30.         }

  31.         // Destroy retired event sources.
  32.         /* 如注释所说,删除retired描述符*/
  33.         if (retired) {
  34.             fds.erase (std::remove_if (fds.begin (), fds.end (),
  35.                 zmq::select_t::is_retired_fd), fds.end ());
  36.             retired = false;
  37.         }
  38.     }
  39. }
这个工作线程很简单,为什么?因为这里的设计非常好,zeromq使用struct i_poll_events作为event对象。这样,将具体的时间处理与工作线程进行了充分的解耦。对于工作线程来说,只需要关心event即可,而无需关心究竟是哪种event,要做何种操作。套一下设计模式的概念,这个设计是命令模式。event即为命令。命令调用者和命令执行者,通过命令消除了关联,简化了命令调用者的逻辑。

还是面向对象的语言应用设计模式,更符合本身语言的语义。如果是C,不是不可以应用这种模式,只不过需要将编译器自动实现的东西如虚函数等,使用C的语法作出类似的实现。

这里再简单的说一下我看zeromq源码的目的。主要是听了crazyhadoop的建议。确实,zeromq的C++的代码写得还是挺漂亮的——就目前看到的代码而言。其实我自身的工作中,基本上是不会有用到zeromq的可能性,所以看它的源码,就是为了学习一下zeromq的设计和C++代码的应用。到目前为止,感觉还是对C++的帮助更大一些。因为我工作中并不使用C++,所以就实际的性价比对我来说,收益并不高,所以以后对zeromq的学习会再次放慢速度。

说了一大堆闲话,今天和crazyhadoop讨论些问题,所以时间不早了。今天的zeromq的源码学习就这样了——很短,只有这个工作线程。
阅读(971) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~