일반적인 스레드 풀 디자인의 간단한 다이어그램에서 실제 스레드 풀과 유사한 처리 실제 시나리오, nginx + 부분 소스를 시뮬레이션하는 C++로 작성된 단일 연결 목록 조직 작업 대기열의 간단한 스레드 풀 구현에 이르기까지 스레드 풀 디자인 nginx의 코드 분석

라이프 인스턴스의 전체 추상 스레드 풀, 사실 스레드 풀은 실제로 코어가 작업 대기열, 작업 대기열 + 뮤텍스 + 조건 변수의 설계에 있다는 느낌을 주어 질서 있는 생산 작업과 처리 작업을 보장합니다. 작업 대기열의 작업 .......

이 풀: 사실 미리 여러 ​​개의 무한 루프 처리 작업을 열어 둔 작업자 스레드입니다. 이러한 여러 스레드는 실제 작업 창과 같고 작업 큐는 우리가 일하러 가는 사람과 같습니다...

사진을 보세요: 은행에서 심부름을 하기 위해 줄을 서거나 병원에서 등록을 하는 사람들 :

사실 이 창은 우리의 작업자 스레드입니다. 실제로 처음부터 자신의 작업 흐름을 알고,,,, 무한 루프에서 작업을 기다립니다.,,,, 미리 열려 있고,,, 항상 준비되어 있으므로 Before 작업이 도착하면 스레드 풀이 생성되고 스레드 풀이 초기화되자마자 이 작업자 스레드를 즉시 시작해야 합니다... (InitTreadPool이 소비자 스레드를 시작함)  

작업자 스레드 : 일반적으로 항상 무한 루프에 있으며 작업 도착을 기다리고 언제든지 작업을 처리할 준비가 되어 있습니다 ......

Task Queue : 생산자, 해결해야 할 작업의 논스톱 생산 및 저장... (비동기 디커플링이 있습니까????).....

먼저 비동기식 디커플링이 무엇인지 이해합시다?????    

대기열 . . . 사실 항상 함수, 버퍼링, 디커플링,,, 그리고 디커플링에 관해서는 항상 비동기식 디커플링이라는 용어가 있지만 이 개념은 과거에는 항상 매우 모호했습니다. . . . . . .

비동기식 디커플링: 즉, 두 이벤트가 대기 관계에서 상호 해제됩니다.,,,, (이것은 저의 단순한 이해입니다. 잘못된 것이 있으면 수정을 환영합니다. 매우 감사하겠습니다.,,,,)

작업 대기열 사용: 실제로 모든 스레드가 사용 중일 때 작업을 제공하는 스레드는 스레드가 유휴 상태가 될 때까지 기다릴 필요가 없습니다. 작업 제출 정보 모직물????

대답은 물론 아니오입니다. 우리는 작업을 작업 대기열에 주기만 하면 됩니다. 걱정할 필요가 없습니다. 직접 반환할 수 있습니다. 이렇게 하면 바쁜 작업자 스레드의 영향을 받지 않고, 작업을 제공하는 스레드 작업을 작업 대기열에 넣으면 계속해서 다른 작업 정보를 가져와 작업 대기열에 넣을 수 있습니다......   

생활 속 택배의 예를 통해서도 이해할 수 있습니다.

예를 들어 일반 신인역에서 택배기사가 특급패키지(태스크)를 신인역에 넣으면 OK... 그러면 택배는 다른 일을 하기 위해 떠날 수 있습니다...

마찬가지로, 우리가 택배를 픽업하러 갈 때 택배와 직접 상호 작용할 필요가 없으며 택배가 택배를 신인 스테이션에 넣었다는 의미도 아닙니다. 우리는 즉시 픽업해야하며 필요하지 않습니다. 먼저 택배를 손에 넣습니다.. 시간을 들여서 물건을 받아도 괜찮습니다...

위의 내용은 비동기식 디커플링에 대한 나의 이해입니다. 즉, 생산자의 경우 사용자가 소비할 때까지 기다릴 필요가 없습니다. 생산할 것입니다. 생산 후 대기열에 넣을 수 있습니다. 소비자가 생산한다는 의미는 아닙니다. 그리고 바로 소비해야 하고, 스스로 소비할 수 있을 때까지 기다려야 하고,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,

쓰레드풀이 이론을 너무 많이 해서 다들 지루해 하실 것 같아요.. 다들 학생이면 빨리 코딩을 하러 오는 것 같아요,,,, 여기서 배울때는 완전 아이디어였거든요, 하하하. 당신은 두 가지 일반적인 아이디어입니다.코드는 다음과 같습니다: C++ 버전

코드를 먼저 작성할 때 한 가지 사항을 이해해야 합니다. 스레드 처리 함수의 첫 번째 매개변수는 void* 유형이어야 합니다.

 void *(*start_routine) (void *) 따라서 이 루틴 스레드에 의해 실행되는 함수는 클래스에서 정적이어야 합니다. 그렇지 않으면 기본적으로 전달되는 첫 번째 매개변수가 this 포인터이며 오류를 보고하므로 이를 다음으로 처리합니다. 정적 함수, 이 포인터 구현을 수동으로 전달

thread_pool의 코드는 다음과 같습니다. [tangyujie@VM-4-9-centos PthreadPool]$ cat pthread_pool.hpp

#pragma once
#include <iostream>
#include <queue>
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>
using std::endl;
using std::cin;
using std::cout;
using std::queue;

template<class T>
class PthreadPool {
public:
    PthreadPool(int num = 3) :_num(num) {
        pthread_mutex_init(&_lock, NULL);
        pthread_cond_init(&_cond, NULL);
    }
    ~PthreadPool() {
        pthread_mutex_destroy(&_lock);
        pthread_cond_destroy(&_cond);
    }
    void Lock() {
        pthread_mutex_lock(&_lock);             //上锁
    }
    void Unlock() {
        pthread_mutex_unlock(&_lock);           //解锁
    }
    void WakeUp() {                             //唤醒进程, 通知消费者线程有任务了
        pthread_cond_signal(&_cond);            //唤醒单个进程
    }
  void Wait() {                                 //没有任务, 消费者线程先阻塞起来等待任务 
        pthread_cond_wait(&_cond, &_lock);        
    }
    bool IsEmptyQueue() {
        return _taskqueue.empty();
    }
    static void* Routine(void* args) {          
        PthreadPool* self = (PthreadPool*)args;   
        while (1) {                      
            self->Lock();                           
            while (self->IsEmptyQueue()) {       //while  防止伪唤醒,
                //wait
                self->Wait();
            }
            //说明存在 task了/
            T t;
            self->PopTask(t);
            self->Unlock();                         
            t.Run();                            //解锁后处理任务.... 做啥???
        }
    } 
    void PushTask(const T& in) {                //传入参数, push task
        Lock();
        _taskqueue.push(in);                    //操作临界资源加锁
        Unlock();
        WakeUp();                                       
    }
    void PopTask(T& out) {                       //传出参数 拿取任务
        out = _taskqueue.front();                //拿取pop任务
        _taskqueue.pop();                        //任务队列pop 任务
    }
    void InitPthreadPool() {                       
        pthread_t tid;        
        for (int i = 0; i < _num; ++i) {
            pthread_create(&tid, NULL, Routine, this);
            pthread_detach(tid);                 //回收线程资源
        }
    }
private:
    int _num;                                   //工作线程的数目
    queue<T> _taskqueue;                        //任务队列
    pthread_mutex_t _lock;                      //锁保证临界资源的互斥访问
    pthread_cond_t _cond;                       //条件变量控制资源到来时候的唤醒工作
};

그런 다음 task.hpp의 코드 생성 작업이 있습니다. #[tangyujie@VM-4-9-centos PthreadPool]$ cat task.hpp

#pragma once
#include <iostream>
#include <pthread.h>
using std::endl;
using std::cout;
using std::cerr;
//typedef int (*handler_t ) (int, int, char);

class Task {
public:
    Task(int x = 1, int y = 1, char op = '+')                //默认构造 
        : _x(x)
        , _y(y)
        , _op(op)  
    {}
    ~Task(){}
    void Run() {
        int z = 0;
        switch(_op) {
            case '+':
                z = _x + _y;
                break;
            case '-':
                z = _x - _y;
                break;
            case '*':
                z = _x * _y;
                break;
            case '/':
                if (_y == 0) {cerr << "div zero!" << endl; break;}
                z = _x / _y;
                break;
            case '%':
                if (_y == 0) {cerr << "mod zero!" << endl; break;}
                z = _x % _y;
                break;
            default:
                cerr << "operator error!" << endl;
                break;
        } 
        cout << "thread: [" << pthread_self() << "]: "<< _x << _op << _y << "=" << z << endl; 
    }
private:
    int _x;
    int _y;
    char _op;
};

마지막은 테스트 함수 main.cc의 코드입니다. [tangyujie@VM-4-9-centos PthreadPool]$ cat main.cc

#include "task.hpp"
#include "pthread_pool.hpp"
#include <cstdlib>
#include <ctime>

int main() {
    PthreadPool<Task> * tp = new PthreadPool<Task>();
    tp->InitPthreadPool();
    srand((unsigned long)time(nullptr));
    const char* ops = "+-*/%";
    while (1) {
        int x = rand() % 123 + 1;
        int y = rand() % 123 + 1;
        Task t(x, y, ops[rand() % 5]);
        tp->PushTask(t);
    sleep(1);
    }
    return 0;
}

 지금까지: 기본적으로 이론은 기본적으로 스레드 풀에 대해 알려져 있습니다. 

 그럼 쓰레드 풀이 좋은 이유를 소개 ???? 풀링 기술의 장점은 무엇인가요????

우선 실 풀, 풀, 풀용, 제 인상은 저수지의 느낌입니다. 예를 들어 물 부족의 최하층에 있는 경우, 집에 물이 많이 필요한 경우, 먼 곳으로 이동해야 하는 경우 물 길러라, 물 필요로 하는 사람도 있구나. 물은 제때만 깹니다....그럴까요??? 당연하겠지만, 필요할 때 물을 가져오는 데 시간이 많이 걸리나요? 물이나 멀리서 물을 운반하러 갈까? 미리 풀장을 만들어 두면 필요하다면 풀장으로 직접 가서 가져오는 것이 훨씬 효율적이지 않을까..............

메모리 풀과 스레드 풀은 실제로 일반적인 풀링 기술입니다. 스레드 풀은 많은 수의 스레드가 일시적으로 생성되는 것을 방지하고 스레드의 재사용을 완전히 실현합니다. 처음 생성된 원래 스레드 풀을 재사용할 수 있습니다. 스레드(작업자 스레드)

이제부터 : 임시 요약글이군요,,,, 제가 너무 많이 썼네요,,,,,,, 다 제 주관적인 생각이고요, 도움이 되셨다면 좋아요, 댓글 환영, 드디어 끝났습니다, 더 이상은, 새해 복 많이 받으세요 배우세요 완성된 작업.... 소스코드의 nginx 부분에 대한 분석은 다음에 써보도록 하겠습니다

추천

출처blog.csdn.net/weixin_53695360/article/details/122745816