• TinyWebServer学习笔记-threadpool


    线程池的特点:

    • 空间换时间,浪费服务器的硬件资源,换取运行效率.

    • 池是一组资源的集合,这组资源在服务器启动之初就被完全创建好并初始化,这称为静态资源.

    • 当服务器进入正式运行阶段,开始处理客户请求的时候,如果它需要相关的资源,可以直接从池中获取,无需动态分配.

    • 当服务器处理完一个客户连接后,可以把相关的资源放回池中,无需执行系统调用释放资源.

     工作流程:

            采用Proactor并发模型,主线程负责监听文件描述符,接受socket连接,若当前监听的socket发生了读写事件,就把任务插入到请求队列中,工作线程从请求队列中取出任务,完成读写数据的处理。

    线程池的定义如下:

    1. template <typename T>
    2. class threadpool
    3. {
    4. public:
    5. /*thread_number是线程池中线程的数量,max_requests是请求队列中最多允许的、等待处理的请求的数量*/
    6. threadpool(int actor_model, connection_pool *connPool, int thread_number = 8, int max_request = 10000);
    7. ~threadpool();
    8. bool append(T *request, int state);
    9. bool append_p(T *request);
    10. private:
    11. /*工作线程运行的函数,它不断从工作队列中取出任务并执行之*/
    12. static void *worker(void *arg);
    13. void run();
    14. private:
    15. int m_thread_number; //线程池中的线程数
    16. int m_max_requests; //请求队列中允许的最大请求数
    17. pthread_t *m_threads; //描述线程池的数组,其大小为m_thread_number
    18. std::list<T *> m_workqueue; //请求队列
    19. locker m_queuelocker; //保护请求队列的互斥锁
    20. sem m_queuestat; //是否有任务需要处理
    21. connection_pool *m_connPool; //数据库
    22. int m_actor_model; //模型切换
    23. };
    24. template <typename T>
    25. threadpool<T>::threadpool( int actor_model, connection_pool *connPool, int thread_number, int max_requests) : m_actor_model(actor_model),m_thread_number(thread_number), m_max_requests(max_requests), m_threads(NULL),m_connPool(connPool)
    26. {
    27. if (thread_number <= 0 || max_requests <= 0)
    28. throw std::exception();
    29. m_threads = new pthread_t[m_thread_number];
    30. if (!m_threads)
    31. throw std::exception();
    32. for (int i = 0; i < thread_number; ++i)
    33. {
    34. if (pthread_create(m_threads + i, NULL, worker, this) != 0)
    35. {
    36. delete[] m_threads;
    37. throw std::exception();
    38. }
    39. if (pthread_detach(m_threads[i]))
    40. {
    41. delete[] m_threads;
    42. throw std::exception();
    43. }
    44. }
    45. }
    46. template <typename T>
    47. threadpool<T>::~threadpool()
    48. {
    49. delete[] m_threads;
    50. }
    51. template <typename T>
    52. bool threadpool<T>::append(T *request, int state)
    53. {
    54. m_queuelocker.lock();
    55. if (m_workqueue.size() >= m_max_requests)
    56. {
    57. m_queuelocker.unlock();
    58. return false;
    59. }
    60. request->m_state = state;
    61. m_workqueue.push_back(request);
    62. m_queuelocker.unlock();
    63. m_queuestat.post();
    64. return true;
    65. }
    66. template <typename T>
    67. bool threadpool<T>::append_p(T *request)
    68. {
    69. m_queuelocker.lock();
    70. if (m_workqueue.size() >= m_max_requests)
    71. {
    72. m_queuelocker.unlock();
    73. return false;
    74. }
    75. m_workqueue.push_back(request);
    76. m_queuelocker.unlock();
    77. m_queuestat.post();
    78. return true;
    79. }
    80. template <typename T>
    81. void *threadpool::worker(void *arg)
    82. {
    83. threadpool *pool = (threadpool *)arg;
    84. pool->run();
    85. return pool;
    86. }
    87. template <typename T>
    88. void threadpool<T>::run()
    89. {
    90. while (true)
    91. {
    92. m_queuestat.wait();
    93. m_queuelocker.lock();
    94. if (m_workqueue.empty())
    95. {
    96. m_queuelocker.unlock();
    97. continue;
    98. }
    99. T *request = m_workqueue.front();
    100. m_workqueue.pop_front();
    101. m_queuelocker.unlock();
    102. if (!request)
    103. continue;
    104. if (1 == m_actor_model)
    105. {
    106. if (0 == request->m_state)
    107. {
    108. if (request->read_once())
    109. {
    110. request->improv = 1;
    111. connectionRAII mysqlcon(&request->mysql, m_connPool);
    112. request->process();
    113. }
    114. else
    115. {
    116. request->improv = 1;
    117. request->timer_flag = 1;
    118. }
    119. }
    120. else
    121. {
    122. if (request->write())
    123. {
    124. request->improv = 1;
    125. }
    126. else
    127. {
    128. request->improv = 1;
    129. request->timer_flag = 1;
    130. }
    131. }
    132. }
    133. else
    134. {
    135. connectionRAII mysqlcon(&request->mysql, m_connPool);
    136. request->process();
    137. }
    138. }
    139. }

    详细解释下work函数,这个函数不断的检查队列是否为空,如果不为空会唤醒线程,在处理任务前获取锁。从任务队列头部取出任务,释放锁,如果取出的任务对象是有效指针,如果是Proactor并发模型代表有数据要读,调用函数读取客户端数据,标记请求已被处理,获得数据库连接执行数据库操作。

    如果读取失败,表示需要进行定时器的处理,如果m_stat=1,那么表示要写入数据,写入成功标记请求已经被处理,否则设置定时器。

    如果不是Proactro模型,那么直接处理请求。

  • 相关阅读:
    【Python练习】task-07 函数的扩展应用
    MySQL中的索引和事务
    10、Python函数命名空间、作用域(LEGB)及Global
    mapstruct常见错误及解决方案
    VUE3-博客全栈 08-前端
    java-php-python-基于SSM智能社区管理系统计算机毕业设计
    docker打包多架构镜像(manifest)
    优化Bloom的降采样
    Linux 文本操作指令
    Word查找红色文字 Word查找颜色字体 Word查找突出格式文本
  • 原文地址:https://blog.csdn.net/pan_1214_/article/details/133526967