mongoose之master_thread函数

mongoose采用了生产者-消费者模式来运作,即一端接受连接(生产),另一端处理连接(消费),如此反复master_thread()函数采用了select的I/O复用模式,相信这也是有评论称mongoose效率不高的原因。因为select函数原型如下

int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
nfds为待检查的套接字描述符的最大值还要加1,这是因为nfds 是待检查的套接字的个数,而 文件描述符是从0开始的。select检查多大nfds个描述符,其中很多未必有用,但是也要检查,这就增加了系统额外的负担。master_thread()所做的事就是把mg_context结构体内的所有待监听的套接字加入监听队列并监听,select检查到有连接到来时进入处理新连接的过程。也就是调用accept函数接受一个新到来的连接,成功接受该连接请求后先要通过访问控制列表的过滤,通过过滤的连接将被加入待消费队列等待另一个线程来消费掉他。

个人觉得mongoose设计的很严谨,结构层层深入,很清晰。既然提到了生产者就要顺便提一下produce_socket()函数了,该函数负责把新连接加入待消费队列。函数原型如下

// Master thread adds accepted socket to a queue
static void produce_socket(struct mg_context *ctx, const struct socket *sp) 
{
  (void) pthread_mutex_lock(&ctx->mutex);

  // If the queue is full, wait
  while (ctx->stop_flag == 0 &&
         ctx->sq_head - ctx->sq_tail >= (int) ARRAY_SIZE(ctx->queue)) 
  {
    (void) pthread_cond_wait(&ctx->sq_empty, &ctx->mutex);
  }

  if (ctx->sq_head - ctx->sq_tail < (int) ARRAY_SIZE(ctx->queue)) 
  {
    // Copy socket to the queue and increment head
    ctx->queue[ctx->sq_head % ARRAY_SIZE(ctx->queue)] = *sp;
    ctx->sq_head++;
    DEBUG_TRACE(("queued socket %d", sp->sock));
  }

  (void) pthread_cond_signal(&ctx->sq_full);
  (void) pthread_mutex_unlock(&ctx->mutex);
}
线程间涉及到操作公共资源 一般都要用到 互斥锁以保证资源不被损坏。如果套接字队列已满的话则等待直到接收到有套接字处理的信号为止。然后把新连接放入队列。该队 一个ringbuf环形存储结构,这个结构相当灵活,只需要3个变量就可以组成一个ringbuf:一个指示头的变量,一个指示尾位置的变量以及一个载体。初始化时头尾相等,增加一个元素时头加1,减少一个元素时尾加1。ringbuf避免了频繁内存分配,很适合用在需要频繁分配内存的地方,例如视频采集。至此mongoose的生产过程已经介绍完了。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值