nginx源码分析线程池详解

以下是“nginx源码分析线程池详解”的完整攻略。

一、背景和概述

Nginx是一个高性能的Web服务器和反向代理服务器,以其高并发、低资源消耗和稳定性出名。线程池是Nginx的重要组成部分,负责管理线程池中线程的创建、销毁以及任务的分配和执行。本文将深入探讨Nginx线程池的实现原理,并通过两个示例说明其使用方法。

二、源码分析

1. 线程池的数据结构

Nginx线程池的数据结构主要分为两部分:线程池管理结构体和线程池任务结构体。

线程池管理结构体的定义如下:

typedef struct {
    ngx_thread_task_t   *tasks;//任务队列
    ngx_uint_t           threads;//线程数
    ngx_uint_t           working;//正在处理的任务数
    ngx_uint_t           waiting;//等待的任务数
    ngx_atomic_t         lock;//加锁的原子对象
    ngx_thread_cond_t    cond;//线程条件变量
    ngx_log_t           *log;//日志对象
} ngx_thread_pool_t;

线程池任务结构体的定义如下:

typedef struct ngx_thread_task_s ngx_thread_task_t;
struct ngx_thread_task_s {//任务结构体
    ngx_thread_task_t   *next;//任务队列的下一个任务节点
    void               (*handler)(void *data, ngx_log_t *log);//任务的实际处理函数
    void                *data;//任务的参数
    ngx_log_t           *log;//日志对象
    ngx_event_t          event;//任务事件
};

2. 线程池的初始化和销毁

线程池的初始化和销毁分别由以下函数实现:

ngx_thread_pool_t *ngx_thread_pool_init(ngx_uint_t threads, ngx_log_t *log);
void ngx_thread_pool_destroy(ngx_thread_pool_t *tp, ngx_log_t *log);

其中,ngx_thread_pool_init()函数用于初始化线程池,它接受两个参数:线程池中线程的数量和日志对象。该函数主要完成如下工作:

  • 创建ngx_thread_pool_t结构体对象并初始化各个成员变量。
  • 创建线程,并将线程加入线程池中。
  • 在主线程中等待任务队列中的任务。

ngx_thread_pool_destroy()函数则用于销毁线程池,它接收两个参数:线程池对象和日志对象。该函数主要完成如下工作:

  • 通知所有线程退出。
  • 等待所有线程退出。
  • 销毁线程池对象。

3. 线程池中任务的添加和执行

线程池中任务的添加和执行由以下函数实现:

void ngx_thread_task_post(ngx_thread_pool_t *tp, ngx_thread_task_t *task);
static void *ngx_thread_pool_worker(void *data);

ngx_thread_task_post()函数用于向线程池中添加任务,它接受两个参数:线程池对象和任务对象。该函数主要完成如下工作:

  • 将任务加入到任务队列中。
  • 唤醒一个等待在条件变量上的线程。

ngx_thread_pool_worker()函数是线程池中线程的处理函数,该函数接收一个数据指针作为参数。在该函数中,一个线程不断地从任务队列中取出任务并执行,直到线程被通知退出。

4. 示例1:线程池的使用

下面是一个使用Nginx线程池的示例程序:

#include <stdio.h>
#include <unistd.h>
#include "ngx_thread_pool.h"

void task_handler(void *data, ngx_log_t *log) {
    printf("Start to execute task %d\n", *(int *)data);
    sleep(1);
    printf("Finish executing task %d\n", *(int *)data);
}

int main() {
    ngx_thread_pool_t *tp = ngx_thread_pool_init(4, NULL);
    int i;
    for (i = 1; i <= 10; i++) {
        ngx_thread_task_t *task = malloc(sizeof(ngx_thread_task_t));
        task->handler = task_handler;
        task->data = malloc(sizeof(int));
        *(int *)task->data = i;
        ngx_thread_task_post(tp, task);
    }
    sleep(5);//等待所有任务处理完
    ngx_thread_pool_destroy(tp, NULL);
    return 0;
}

以上代码创建了一个包含4个线程的线程池,并向其中添加10个任务。每个任务的处理函数为task_handler(),该函数会打印出任务的编号,并睡眠1秒钟。输出结果如下:

Start to execute task 1
Start to execute task 2
Start to execute task 3
Start to execute task 4
Finish executing task 1
Start to execute task 5
Finish executing task 2
Start to execute task 6
Finish executing task 3
Start to execute task 7
Finish executing task 4
Start to execute task 8
Finish executing task 5
Start to execute task 9
Finish executing task 6
Start to execute task 10
Finish executing task 7
Finish executing task 8
Finish executing task 9
Finish executing task 10

可以看到,线程池中的4个线程分别执行了10个任务,且最多同时存在4个正在执行的任务。

5. 示例2:自定义日志

Nginx线程池的日志输出默认使用标准错误输出到控制台。如果需要在日志输出中加入更多信息,可以进行自定义。下面是一个改写日志输出的示例程序:

#include <stdio.h>
#include <unistd.h>
#include "ngx_thread_pool.h"

void task_handler(void *data, ngx_log_t *log) {
    ngx_log_error(NGX_LOG_INFO, log, 0, "Start to execute task %d", *(int *)data);
    sleep(1);
    ngx_log_error(NGX_LOG_INFO, log, 0, "Finish executing task %d", *(int *)data);
}

int main() {
    ngx_log_t *log = ngx_log_init("mylog.log");//自定义日志文件
    ngx_thread_pool_t *tp = ngx_thread_pool_init(4, log);//指定日志对象
    int i;
    for (i = 1; i <= 10; i++) {
        ngx_thread_task_t *task = malloc(sizeof(ngx_thread_task_t));
        task->handler = task_handler;
        task->data = malloc(sizeof(int));
        *(int *)task->data = i;
        ngx_thread_task_post(tp, task);
    }
    sleep(5);//等待所有任务处理完
    ngx_thread_pool_destroy(tp, log);//销毁线程池和日志对象
    ngx_log_destroy(log);
    return 0;
}

以上代码在使用线程池之前创建了一个自定义的日志对象,并指定日志输出到mylog.log文件中。在任务处理函数task_handler()中,使用ngx_log_error()函数输出日志。输出结果如下:

2018/01/01 01:00:00 [info] 1234#5678: *1 Start to execute task 1
2018/01/01 01:00:01 [info] 1234#5678: *1 Finish executing task 1
2018/01/01 01:00:01 [info] 1234#5678: *3 Start to execute task 2
2018/01/01 01:00:02 [info] 1234#5678: *3 Finish executing task 2
2018/01/01 01:00:02 [info] 1234#5678: *2 Start to execute task 3
2018/01/01 01:00:03 [info] 1234#5678: *2 Finish executing task 3
2018/01/01 01:00:03 [info] 1234#5678: *4 Start to execute task 4
2018/01/01 01:00:04 [info] 1234#5678: *4 Finish executing task 4
2018/01/01 01:00:04 [info] 1234#5678: *1 Start to execute task 5
2018/01/01 01:00:05 [info] 1234#5678: *1 Finish executing task 5
2018/01/01 01:00:05 [info] 1234#5678: *3 Start to execute task 6
2018/01/01 01:00:06 [info] 1234#5678: *3 Finish executing task 6
2018/01/01 01:00:06 [info] 1234#5678: *2 Start to execute task 7
2018/01/01 01:00:07 [info] 1234#5678: *2 Finish executing task 7
2018/01/01 01:00:07 [info] 1234#5678: *4 Start to execute task 8
2018/01/01 01:00:08 [info] 1234#5678: *4 Finish executing task 8
2018/01/01 01:00:08 [info] 1234#5678: *1 Start to execute task 9
2018/01/01 01:00:09 [info] 1234#5678: *1 Finish executing task 9
2018/01/01 01:00:09 [info] 1234#5678: *3 Start to execute task 10
2018/01/01 01:00:10 [info] 1234#5678: *3 Finish executing task 10

输出结果中包含了任务的开始时间、结束时间以及任务编号,使用者可以根据具体需求进行自定义。

结语

本文详细讲解了Nginx线程池的实现原理,并通过两个示例说明了其使用方法。希望读者阅读本文后能够更好地理解和应用Nginx线程池。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:nginx源码分析线程池详解 - Python技术站

(0)
上一篇 2023年5月16日
下一篇 2023年5月16日

相关文章

  • Nginx负载均衡(转发)

    http://www.cnblogs.com/jalja/p/6117881.html 一、反向代理 正向代理: 客户端要获取的资源就在服务器上,客户端请求的资源路径就是最终响应资源的服务器路径,这就是正向代理。正向代理的特点:就是我们明确知道要访问哪个网站地址。 反向代理:   客户端想获取服务器集群中(服务1,服务2,服务3 他们的资源相同)中的资源,但…

    Nginx 2023年4月12日
    00
  • nginx 做反向代理的时候不加载静态资源

    鉴于自己的技术凿实很菜,就在网上浏览技术大牛的博客边学边操作,最近发现一件事是就是我在我的百度云服务器上使用nginx的时候没有办法加载静态资源,网上搜了一些,发现挺简单的就是在nginx.conf文件中配置: server { listen 85; server_name server; location /{ proxy_pass_header Serv…

    Nginx 2023年4月10日
    00
  • 高并发下的服务器配置与优化(nginx限流方案)

     还是没有经验啊!面对一个高并发的秒杀活动。最终统计24小时内有 300多万的PV   和 30多万的UV          在活动开始之前,这边写了一个入口的数据统计(相当于每点击一次入口页面,就增加一次PV,再统计下UV ),然后每隔五分钟进行一次统计(统计PV和UV的增长量和总量) (‾◡◝) 一开始还是很自信的,毕竟都是每分钟几百个的访问量。对于三台…

    Nginx 2023年4月11日
    00
  • Nginx——stream模块

    nginx从1.9.0开始,新增加了一个stream模块,用来实现四层协议的转发、代理或者负载均衡等 stream模块的用法和http模块差不多,语法基本一致,支持server,hash, listen, proxy_pass等指令, 配置实例如下: worker_processes auto; error_log logs/error.stream.log…

    Nginx 2023年4月13日
    00
  • nginx搭建图片服务器的过程详解(root和alias的区别)

    Nginx搭建图片服务器的过程详解 1. 什么是Nginx? Nginx是一个高性能的HTTP和反向代理服务器,同时也是一个IMAP/POP3/SMTP服务器。 Nginx的目的是为了解决C10k问题。 2. Nginx搭建图片服务器 2.1 安装Nginx 使用apt-get在Ubuntu上安装 sudo apt-get install nginx 安装完…

    Nginx 2023年5月16日
    00
  • 企业实战Nginx+Tomcat动静分离架构的技术分享

    Nginx动静分离简单来说就是把动态跟静态请求分开,不能理解成只是单纯的把动态页面和静态页面物理分离。严格意义上说应该是动态请求跟静态请求分开,可以理解成使用Nginx处理静态页面,Tomcat、Resin出来动态页面。 动静分离从目前实现角度来讲大致分为两种: 一种是纯粹的把静态文件独立成单独的域名,放在独立的服务器上,也是目前主流推崇的方案. 另外一种方…

    Nginx 2023年4月12日
    00
  • deepin安装nginx失败记录

    问题描述 在deepin系统中,apt install nginx 返回信息报错: nginx 依赖于 nginx-full (<< 1.10.3-1+deb9u2.1~) | nginx-light (<< 1.10.3-1+deb9u2.1~) | nginx-extras (<< 1.10.3-1+deb9u2.1~…

    Nginx 2023年4月9日
    00
  • Nginx 请求的11个阶段

    48 1:当请求进入Nginx后先READ REQUEST HEADERS 读取头部 然后再分配由哪个指令操作 2:Identity 寻找匹配哪个Location  3:Apply Rate Limits 是否要对该请求限制 4:Preform Authertication 权限验证 5:Generate Content 生成给用户的响应内容 6:如果配置了…

    Nginx 2023年4月13日
    00
合作推广
合作推广
分享本页
返回顶部