Http Thread Pool Design and Implementation (c ++)
The main purpose of the http thread pool is to asynchronously process http requests that use stateless transient connections. The transport layer communication is based on the tcp protocol and the application layer based on the http protocol, this allows the c ++ server to communicate with the web server.
Design:
(1) initialize the number of threads configured during server startup (forming a passive connection thread pool ). Each thread generates an epoll descriptor.
(2) The main thread generates a listening socket and binds the port. Generate the epoll Descriptor and register the listening socket. Non-blocking reception (limited maximum time, such as 2 s) is newly connected to the connection queue.
(2) The new connection to the passive connection thread pool in the active thread connection queue. Select the required thread Based on the hard hash. After joining, You need to register the connection socket (when the connection object is registered as the epoll event carrying data) to the epoll descriptor of the thread.
(3) In each thread's routine, read events on the epoll descriptor will be monitored without blocking, and the obtained http requests will be parsed and processed.
In this way, each service thread can process stateless http requests independently. In different scenarios, the data sharing between threads in the http thread pool should be minimized (locks are required if the cache is in the memory ), each thread can be used as a client to block requests to other servers for a short time.
The http thread pool code is as follows: (generally, the idea of the http thread pool can be seen. The implementation process is not shown here when the main thread receives data from the connection object and connection object. Note that the EINTR and SIGPIPE signals must be ignored during receiving. If-1 is returned and the error code is EAGAIN or EWOULDBLOCK, it indicates that the receiving buffer is full and you need to continue receiving until the receiving times out. If 0 is returned for receiving, the other party is disconnected and the receiving fails. The connection object (epoll descriptor deregister the connection socket, close the socket, remove and destroy the connection object) needs to be removed for successful reception, failure, and timeout, because it is a short connection)
Thread Pool header file
/*** Rief defines the http service framework class for lightweight implementation (lightweight) */class zHttpTaskPool: private zNoncopyable {public:/*** rief constructor */zHttpTaskPool () {}/*** rief destructor, destroys a thread pool object **/~ ZHttpTaskPool () {final ();} bool addHttp (zHttpTask * task); bool init (); void final (); private: static const int maxHttpThreads = 16; /** <maximum number of verification threads */zThreadGroup httpThreads;/**
Source file of Thread Pool
/*** Main processing thread of rief lightweight http service */class zHttpThread: public zThread {private:/*** rief http connection task linked list type */typedef std: list
ZHttpTaskContainer;/*** rief epoll Event Structure vector type */www. bkjia. comtypedef std: vector
EpollfdContainer; zHttpTaskPool * pool;/** <pool */zRTime currentTime;/** <current time */zMutex mutex;/** <mutex variable */zHttpTaskContainer tasks; /** <task list */int kdpfd; epollfdContainer epfds; epollfdContainer: size_type fds_count; public: /*** rief constructor * connection pool * param name thread name */zHttpThread (zHttpTaskPool * pool, const std: string & name = std :: string (zHttpThread): zThread (name), pool (pool), currentTime () {Kdpfd = epoll_create (256); assert (-1! = Kdpfd); epfds. resize (256); fds_count = 0;}/*** rief destructor */~ ZHttpThread () {TEMP_FAILURE_RETRY (: close (kdpfd);} void run (); /*** rief add a connection task * param task connection task */void add (zHttpTask * task) {mutex. lock (); task-> addEpoll (kdpfd, EPOLLIN | EPOLLERR | EPOLLPRI, (void *) task); tasks. push_back (task); ++ fds_count; if (fds_count> epfds. size () {epfds. resize (fds_count + 16);} mutex. unlock ();} typedef zHttpTask * zHttpTaskP; void remove (zHttpTaskP & task) {task-> delEpoll (kdpfd, EP OLLIN | EPOLLERR | EPOLLPRI); tasks. remove (task); SAFE_DELETE (task); fds_count --;} void remove (zHttpTaskContainer: iterator & it) {zHttpTask * task = * it; task-> delEpoll (kdpfd, EPOLLIN | EPOLLERR | EPOLLPRI); tasks. erase (it); SAFE_DELETE (task); fds_count -- ;}};/*** rief http thread routine */void zHttpThread: run () {zHttpTaskContainer: iterator it, next; while (! IsFinal () {mutex. lock (); if (! Tasks. empty () {int retcode = epoll_wait (kdpfd, & epfds [0], fds_count, 0); if (retcode> 0) {for (int I = 0; I <retcode; ++ I) {zHttpTask * task = (zHttpTask *) epfds [I]. data. ptr; // obtain the epoll event data, that is, the connection object if (epfds [I]. events & (EPOLLERR | EPOLLPRI) // check whether the epoll event is wrong {// an error occurs on the set of interfaces remove (task);} else if (epfds [I]. events & EPOLLIN) // check whether the epoll event is a read event {switch (task-> httpCore () // block the recv connection object buffer data {case 1: // received successfully case-1: // failed to receive remov E (task); break; case 0: // receiving timeout, break ;}}} currentTime. now (); for (it = tasks. begin (), next = it, ++ next; it! = Tasks. end (); it = next, ++ next) // check the transient connection object and remove the timeout connection object {zHttpTask * task = * it; if (task-> checkHttpTimeout (currentTime) {// The verification has not passed after the specified time. You need to recycle the connection remove (it) ;}} mutex. unlock (); zThread: msleep (50) ;}// add all connections in the waiting for verification queue to the recycle queue and recycle these connections for (it = tasks. begin (), next = it, ++ next; it! = Tasks. end (); it = next, ++ next) {remove (it) ;}/ *** rief adds a TCP connection to the validation queue, because there are multiple authentication queues, you need to add them to different Authentication Queue according to certain algorithms * param task a connection task */bool zHttpTaskPool: addHttp (zHttpTask * task) {// because there are multiple verification queues, you need to add them to different verification Queue according to certain algorithms static unsigned int hashcode = 0; zHttpThread * pHttpThread = (zHttpThread *) httpThreads. getByIndex (hashcode ++ % maxHttpThreads); if (pHttpThread) pHttpThread-> add (task); return true;}/*** rief initialization line Thread Pool, pre-create various threads * eturn initialization successful */bool zHttpTaskPool: init () {// create initialization verification thread for (int I = 0; I <maxHttpThreads; ++ I) {std: ostringstream name; name <zHttpThread [<I <]; zHttpThread * pHttpThread = new zHttpThread (this, name. str (); if (NULL = pHttpThread) return false; if (! PHttpThread-> start () return false; httpThreads. add (pHttpThread);} return true;}/*** rief releases the thread pool, releases various resources, and waits for various threads to exit */void zHttpTaskPool: final () {httpThreads. joinAll ();}