一、C线程库
1. 创建线程
int pthread_create(
pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *),
void *arg
);
注意:
- 函数原型中第三个参数的类型为函数指针,指向的线程的处理函数,其参数类型为(void *)。
- 若线程函数为类成员函数,则this指针会作为默认的参数被传进函数中,从而和线程函数的参数(void*)不能匹配,不能通过编译。
- 由于类的静态成员函数没有this指针,不会出现问题。
2. 退出线程
- 一般情况下,针对于主线程,如果想要让线程退出,且不影响到其他线程的正常运行,即不释放虚拟地址空间
void pthread_exit(
void *retval
);
3. 回收线程
- 如果子线程在运行,调用该函数的线程就会阻塞,子线程退出后,函数解除阻塞进行资源回收。
- 函数被调用一次,只能回收一个子线程,如果有多个子线程则需要循环进行回收。
int pthread_join(
pthread_t thread,
void **retval
);
4. 线程分离
- 一般情况下,程序中的主线程有其他任务,如果让主线程负责子线程的资源回收, 只要子线程不退出主线程就会一直被阻塞。
- 子线程与主线程分离之后,子线程退出后其占用的内核资源就被系统的其他进程接管并回收了。
int pthread_detach(pthread_t thread);
二、实现代码
#ifndef THREADPOOL_H
#define THREADPOOL_H
#include <list>
#include <cstdio>
#include <exception>
#include <pthread.h>
#include "../lock/locker.h"
#include "../CGImysql/sql_connection_pool.h"
template <typename T>
class threadpool
{
public:
threadpool(int actor_model, connection_pool *connPool, int thread_number = 8, int max_request = 10000);
~threadpool();
bool append(T *request, int state);
bool append_p(T *request);
private:
static void *worker(void *arg);
void run();
private:
int m_thread_number;
int m_max_requests;
pthread_t *m_threads;
std::list<T *> m_workqueue;
locker m_queuelocker;
sem m_queuestat;
connection_pool *m_connPool;
int m_actor_model;
};
template <typename T>
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)
{
if (thread_number <= 0 || max_requests <= 0)
throw std::exception();
this->m_threads = new pthread_t[this->m_thread_number];
if (!this->m_threads)
throw std::exception();
for (int i = 0; i < thread_number; ++i)
{
if (pthread_create(this->m_threads + i, NULL, worker, this) != 0)
{
delete[] this->m_threads;
throw std::exception();
}
if (pthread_detach(this->m_threads[i]))
{
delete[] this->m_threads;
throw std::exception();
}
}
}
template <typename T>
threadpool<T>::~threadpool()
{
delete[] m_threads;
}
template <typename T>
bool threadpool<T>::append(T *request, int state)
{
m_queuelocker.lock();
if (m_workqueue.size() >= m_max_requests)
{
m_queuelocker.unlock();
return false;
}
request->m_state = state;
m_workqueue.push_back(request);
m_queuelocker.unlock();
m_queuestat.post();
return true;
}
template <typename T>
bool threadpool<T>::append_p(T *request)
{
m_queuelocker.lock();
if (m_workqueue.size() >= m_max_requests)
{
m_queuelocker.unlock();
return false;
}
m_workqueue.push_back(request);
m_queuelocker.unlock();
m_queuestat.post();
return true;
}
template <typename T>
void *threadpool<T>::worker(void *arg)
{
threadpool *pool = (threadpool *)arg;
pool->run();
return pool;
}
template <typename T>
void threadpool<T>::run()
{
while (true)
{
m_queuestat.wait();
m_queuelocker.lock();
if (m_workqueue.empty())
{
m_queuelocker.unlock();
continue;
}
T *request = m_workqueue.front();
m_workqueue.pop_front();
m_queuelocker.unlock();
if (!request)
continue;
if (1 == m_actor_model)
{
if (0 == request->m_state)
{
if (request->read_once())
{
request->improv = 1;
connectionRAII mysqlcon(&request->mysql, m_connPool);
request->process();
}
else
{
request->improv = 1;
request->timer_flag = 1;
}
}
else
{
if (request->write())
{
request->improv = 1;
}
else
{
request->improv = 1;
request->timer_flag = 1;
}
}
}
else
{
connectionRAII mysqlcon(&request->mysql, m_connPool);
request->process();
}
}
}
#endif