Chinaunix首页 | 论坛 | 博客
  • 博客访问: 6948346
  • 博文数量: 159
  • 博客积分: 10424
  • 博客等级: 少将
  • 技术积分: 14594
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-14 12:45
个人简介

啦啦啦~~~

文章分类
文章存档

2015年(5)

2014年(1)

2013年(5)

2012年(10)

2011年(116)

2010年(22)

分类: C/C++

2011-11-22 22:08:28

作者:gfree.wind@gmail.com
博客:blog.focus-linux.net     linuxfocus.blog.chinaunix.net

书接上回,继续的zmq_init的源码分析。上次学习到了zmq::reaper_t::reaper_t中。

  1. zmq::reaper_t::reaper_t (class ctx_t *ctx_, uint32_t tid_) :
  2.     object_t (ctx_, tid_),
  3.     sockets (0),
  4.     terminating (false)
  5. {
  6.     poller = new (std::nothrow) poller_t;
  7.     alloc_assert (poller);
     
     /* 
     上次说到mailbox.get_fd()返回的是一个unix域的读取描述符 
     */
  1.     mailbox_handle = poller->add_fd (mailbox.get_fd (), this);
  2.     poller->set_pollin (mailbox_handle);
  3. }
进入poller->add_fd
  1. zmq::epoll_t::handle_t zmq::epoll_t::add_fd (fd_t fd_, i_poll_events *events_)
  2. {
  3.     /* 一个fd需要一个poll_entry_t */
  4.     poll_entry_t *pe = new (std::nothrow) poll_entry_t;
  5.     alloc_assert (pe);

     /* 
     如注释所说,这个memset为了防止某些编译器报warning
     平时我也遇到过同样的问题。虽然并没有真正使用未初始化的变量,但是某些编译器确实会报警告。
     */
  1.     // The memset is not actually needed. It's here to prevent debugging
  2.     // tools to complain about using uninitialised memory.
  3.     memset (pe, 0, sizeof (poll_entry_t));

  4.     pe->fd = fd_;
  5.     pe->ev.events = 0;
  6.     pe->ev.data.ptr = pe;
  7.     pe->events = events_;
     /* 将fd_加入到epoll_fd对应的epoll的instance */
  1.     int rc = epoll_ctl (epoll_fd, EPOLL_CTL_ADD, fd_, &pe->ev);
  2.     errno_assert (rc != -1);

     /* 增加poller的负载计数 */
  1.     // Increase the load metric of the thread.
  2.     adjust_load (1);

  3.     return pe;
  4. }
进入poller->set_pollin
  1. void zmq::epoll_t::set_pollin (handle_t handle_)
  2. {
  3.     poll_entry_t *pe = (poll_entry_t*) handle_;
        /* 告诉epoll_fd对应的epoll实例,pe->fd已经处于可读取状态 */
  4.     pe->ev.events |= EPOLLIN;
  5.     int rc = epoll_ctl (epoll_fd, EPOLL_CTL_MOD, pe->fd, &pe->ev);
  6.     errno_assert (rc != -1);
  7. }
接下来,回到ctx_t的构造函数:
  1. zmq::ctx_t::ctx_t (uint32_t io_threads_) :
  2.     tag (0xbadcafe0),
  3.     terminating (false)
  4. {
  5.     int rc;

  6.     ......  ......

  7.     // Create the reaper thread.
  8.     reaper = new (std::nothrow) reaper_t (this, reaper_tid);
  9.     alloc_assert (reaper);
  10.     /* 保存reaper的mailbox,用于以后通信 */
  11.     slots [reaper_tid] = reaper->get_mailbox ();
  12.     /* 启动reaper的工作线程*/
  13.     reaper->start ();
     
     ......  ......
  1. }
reaper->start ==> zmq::reaper_t::start ==> zmq::epoll_t::start ==> zmq::thread_t::start

那么现在我们看看zmq::thread_t::start的实现:

  1. extern "C"
  2. {
  3.     static void *thread_routine (void *arg_)
  4.     {
  5. #if !defined ZMQ_HAVE_OPENVMS
  6.         // Following code will guarantee more predictable latecnies as it'll
  7.         // disallow any signal handling in the I/O thread.
  8.         sigset_t signal_set;
  9.         int rc = sigfillset (&signal_set);
  10.         errno_assert (rc == 0);
  11. # if !defined ZMQ_HAVE_ANDROID
  12.         rc = pthread_sigmask (SIG_BLOCK, &signal_set, NULL);
  13.         posix_assert (rc);
  14. # endif
  15. #endif

 /* 本函数只是一个简单包装,这里直接调用thread_t的tfn,即调用者真正想启动的函数 */
  1.         zmq::thread_t *self = (zmq::thread_t*) arg_;
  2.         self->tfn (self->arg);
  3.         return NULL;
  4.     }
  5. }

  6. void zmq::thread_t::start (thread_fn *tfn_, void *arg_)
  7. {
  8.     /* 保存工作函数和参数 */
  9.     tfn = tfn_;
  10.     arg =arg_;
     /* 
     创建线程,但是这里线程的入口函数并不是参数tfn_,为什么呢?

     为什么不直接pthread_create(&descriptor, NULL, tfn_, arg)呢
     */
  1.     int rc = pthread_create (&descriptor, NULL, thread_routine, this);
  2.     posix_assert (rc);
  3. }
今天遗留下一个问题,就是上面所说的,为什么要多一层thread_routine的封装呢?


阅读(6392) | 评论(1) | 转发(1) |
给主人留下些什么吧!~~

tklist2015-10-09 10:05:11

为什么不直接pthread_create(&descriptor, NULL, tfn_, arg)呢

我觉得作者想在启动函数之前做一些额外工作。比如作者代码的里面的信号屏蔽