错误事件
在做webserver
项目时,将线程池的模板类的声明写在.h
文件,代码如下:
#ifndef THREADPOOL_H
#define THREADPOOL_H
// 引入头文件
#include"../lock/locker.h"
#include<list>
#include<vector>
#include<iostream>
#include<exception>
template<typename T>
class threadPool{
public:
threadPool(int thread_number = 8, int max_requests = 10000);
// 需要注意的是,成员变量的默认值只能在声明里,而不能在定义中
~threadPool();
bool append(T*);
private:
int m_max_requets; // 请求队列中允许的最大请求数量
int m_thread_number; // 线程池中线程数量
std::list<T*> m_queue; // 任务队列
pthread_t* m_threads; // 描述线程池的数组
locker m_queueLocker; // 请求队列的锁
sem m_queueStat; // 是否有任务需要处理
bool m_stop; // 线程结束的标志
// 如果写了数据库,线程池里还需要把数据库的成员变量加上去
/* 线程工作运行的函数,该函数不断地从任务队列中取出任务并执行*/
static void* work(void* args);
/* 静态函数没有this指针,只能操作静态变量 */
void run();
};
#endif
将定义写在.cpp
文件里,代码如下:
#include"threadPool.h"
template<typename T>
threadPool<T>::threadPool(int thread_number, int max_requests)
: m_max_requets(max_requests),
m_thread_number(thread_number),
m_threads(nullptr),
m_stop(false)
{
if(m_max_requets <= 0 || m_thread_number <= 0){
throw std::exception();
}
// 分配存放线程ID的内存空间
m_threads = new pthread_t[m_thread_number];
if(!m_threads){ // 异常处理
throw std::exception();
}
for(int i = 0; i < m_thread_number; ++ i){
std::cout << "创建了第" << i << "th个线程" << std::endl;
if(pthread_create(m_threads + i, nullptr, work, this) != 0){
// 突然明白为什么要使用数组了,因为方便销毁,如果是vector的话,就很难办
delete[] m_threads;
throw std::exception();
}
if(pthread_detach(m_threads[i])){
delete[] m_threads;
throw std::exception();
}
}
}
template<typename T>
threadPool<T>::~threadPool(){
delete[] m_threads; // 这一步实际上是把存放线程ID的内存释放掉了,并不是释放掉了真正的线程。
// 这是在堆中开辟的内存,使用delete将堆中的内存释放掉
// 释放该内存后,这也相当于释放了线程,那m_stop = true还有必要吗?
// 或者说pthread_t*指针根本不代表线程,释放m_threads并不会真正释放线程资源
// pthread_t确实不表示真正的线程,它的真正类型是unsigned long int
// 表示线程ID,而且它指向的内存与线程资源中的ID所在的内存一定是独立的
// 否则delete就会把线程资源ID释放掉,这也太滑稽了
m_stop = true;
}
template<typename T>
bool threadPool<T>::append(T* request){
m_queueLocker.lock(); // 上锁
if(m_queue.size() + 1 > m_max_requets){
m_queueLocker.unlock();
return false;
}
m_queue.push_back(request);
m_queue.unlock(); // 解锁
m_queueStat.post(); // 信号量加1
// 表明有任务到达,唤醒等待队列中阻塞的线程
return true;
}
template<typename T>
void* threadPool<T>::work(void* args){
threadPool* pool = static_cast<threadPool*>(args);
pool -> run();
return pool;
}
template<typename T>
void threadPool<T>::run(){
while(!m_stop){
// 判断是否有任务到达,如果没有任务到达,wait()会阻塞该线程
m_queueStat.wait();
m_queueLocker.lock();
if(m_queue.empty()){
m_queueLocker.unlock();
continue;
}
T* request = m_queue.front();
m_queue.pop_front();
m_queueLocker.unlock();
if(!request){
continue;
}
request -> process(); // 处理任务
}
}
// 我好像明白什么是面向对象了
// 对象会提供操作自身的成员函数
// 如果你要处理对象里面的数据,就让对象调用自己的成员函数
// 而对于面向过程的编程,如果你要处理一些数据,需要把这些数据传递给一个函数
// 就比如线程池里,如果使用面向过程的编程,要处理任务,需要把待处理的任务通过指针传递进去
错误情况
结果在编译时报了如下错误:
/tmp/cczG6pBx.o:在函数‘main’中:
main.cpp:(.text+0xce):对‘threadPool<http_conn>::threadPool(int, int)’未定义的引用
main.cpp:(.text+0x4da):对‘threadPool<http_conn>::append(http_conn*)’未定义的引用
main.cpp:(.text+0x607):对‘threadPool<http_conn>::~threadPool()’未定义的引用
collect2: error: ld returned 1 exit status
错误原因
由于时间关系,错误原因稍后补充
解决方案
一般而言,有如下解决方案:
- 将模板类的声明和定义放在同一个
.h
文件里