最近在Linux下使用mysql时有时会报查询异常,看网上解决方案是多次并发使用,通过gdb调试也找到问题,主要是上次查询结果集未释放,最终导致如此。
大佬说根本解决方案还是线程池,就去看了线程池的一些内容,记录此篇主要是用于自己cv,怕自己忘记
1、threadPool.cpp
#include "threadPool.h"
void* threadRoutine(void* arg);
threadPool* createPool(int max_thread_num, int max_task_queue_items) {
threadPool* pool;
pool = (threadPool*)malloc(sizeof(threadPool));
if (pool == nullptr) {
cout << "线程池创建失败" << endl;
goto error_handler;
}
memset(pool, 0, sizeof(threadPool));
pool->max_task_queue_items = max_thread_num;
pool->max_task_queue_items = max_task_queue_items;
pool->threadArray = (pthread_t*)malloc(sizeof(pthread_t) * max_thread_num);
if (pool->threadArray == nullptr) {
cout << "工作线程创建失败" << endl;
goto error_handler;
}
memset(pool->threadArray, 0, sizeof(( sizeof(pthread_t) * max_thread_num)));
pool->task_head = nullptr; //任务队列初始化
if (pthread_mutex_init(&(pool->mutex), nullptr) != 0) {
cout << "互斥锁初始化失败" << endl;
goto error_handler;
}
if (pthread_cond_init(&(pool->task_queue_have_misson), nullptr) != 0) {
cout << "条件变量队列为空初始化失败" << endl;
goto error_handler;
}
if (pthread_cond_init(&(pool->task_queue_have_space), nullptr) != 0) {
cout << "条件变量队列为满初始化失败" << endl;
goto error_handler;
}
/* 工作线程初始化 */
for (int i = 0; i < max_thread_num; i++) {
if ((pthread_create(&(pool->threadArray[i]), nullptr, threadRoutine, (void*)pool) != 0)){
cout << "工作线程创建失败 " << endl;
}
}
return pool;
error_handler:
destroy_pool(pool);
return nullptr;
}
void* threadRoutine(void* arg) {
threadPool* pool = (threadPool*)arg;
while (true){
pthread_mutex_lock(&pool->mutex);
if (pool->task_queue_size == 0) {
cout << "任务队列为空,线程" << (unsigned int)pthread_self() << "挂起" << endl;
pthread_cond_wait(&pool->task_queue_have_misson, &pool->mutex);
}
taskQueue* currentWorker = pool->task_head;
pool->task_head = pool->task_head->next;
pthread_cond_broadcast(&pool->task_queue_have_misson);
pool->task_queue_size--;
pthread_mutex_unlock(&pool->mutex);
cout << "当前线程" << (unsigned int)pthread_self() << "开始工作" << endl;
currentWorker->taskFun(currentWorker->arg);
cout << "当前线程" << (unsigned int)pthread_self()<< "工作完成" << endl;
free(currentWorker);
currentWorker = nullptr;
}
}
void addTask(threadPool* pthis, void* (*taskFun)(void* arg), void* arg) {
threadPool* pool = pthis;
taskQueue* currentTask = nullptr;
pthread_mutex_lock(&pool->mutex);
while (pool->max_task_queue_items == pool->task_queue_size) {
pthread_cond_wait(&pool->task_queue_have_space, &pool->mutex);
}
currentTask->arg = arg;
currentTask->taskFun = taskFun;
currentTask->next = nullptr;
/* 新的任务加到任务队列尾部 */
taskQueue* tempWorker = nullptr;
if(pool->task_head != nullptr){
tempWorker = pool->task_head;
while (tempWorker->next != nullptr) {
tempWorker = tempWorker->next;
}
tempWorker->next = currentTask;
}
else {
pool->task_head->next = currentTask;
}
pool->task_queue_size++;
pthread_cond_signal(&pool->task_queue_have_misson);
free(tempWorker);
pthread_mutex_unlock(&pool->mutex);
}
int destroy_pool(void* pthis) {
threadPool* pool = (threadPool*)pthis;
if (pool == nullptr) {
return -1;
}
taskQueue* head = nullptr;
/*销毁任务队列*/
while (pool->task_head != nullptr){
head = pool->task_head;
pool->task_head = pool->task_head->next;
free(head);
}
for (int i = 0; i < pool->max_thread_num; i++) {
pthread_join(pool->threadArray[i],nullptr);
}
free(pool->threadArray);
pthread_cond_destroy(&pool->task_queue_have_misson);
pthread_cond_destroy(&pool->task_queue_have_space);
pthread_mutex_destroy(&pool->mutex);
return 0;
}
2、threadPool.h
#ifndef __THREAD_POOL_H__
#define __THREAD_POOL_H__
#include <pthread.h>
#include <iostream>
#include <string.h>
using namespace std;
/** 任务队列 **/
struct taskQueue{
void* (*taskFun)(void* arg); //函数指针
void* arg;
struct taskQueue* next;
}; //想法是一个单链表形式的队列
/** 线程池结构 **/
struct threadPool{
int max_thread_num; //最大工作线程数量
int max_task_queue_items; //任务队列最大任务数
int task_queue_size; //当前任务队列任务数
taskQueue* task_head; //任务队列头结点
pthread_t* threadArray; //工作线程数组
pthread_cond_t task_queue_have_space; //任务队列是否满了
pthread_cond_t task_queue_have_misson; //任务队列是否空了
pthread_mutex_t mutex; //互斥锁
};
void addTask(threadPool* pthis, void* (*taskFun)(void* arg), void* arg);
threadPool* createPool(int max_thread_num, int max_task_queue_items);
int destroy_pool(void* pthis);
#endif // !
3、main.cpp
#include <arpa/inet.h>
#include <sys/socket.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include "threadPool.h"
#define port 8080
#define max_thread_num 10
#define max_task_queue_items 100
void error_message(string message){
fputs(message.c_str() , stderr);
fputc('\n' , stderr);
exit(1);
}
void* client_fun(void* arg){
int sock = *((int *) arg);
char buf[1024];
int count = 0;
int sendBytes = -1;
while(1) {
memset(buf, 0, sizeof(buf));
if ((count = recv(sock, buf, 1024, 0)) > 0){
printf("Received a message from %d: %s\n", sock, buf);
/*将数据发给服务器 */
if((sendBytes = send(sock, buf, strlen(buf),0)) == -1){
perror("send");
close(sock);
printf("Client %d(socket) write failure:%s!\n", sock,strerror(errno));
continue;
}
}
else {
close(sock);
printf("Client %d(socket) has left\n", sock);
break;
}
}
printf("\r\n client_server_fun执行完毕\r\n");
return nullptr;
}
int main(){
struct sockaddr_in serv_addr,clnt_addr;
int serv_sock, clnt_sock;
socklen_t clnt_addr_sz;
threadPool* pool = NULL;
pool = createPool(max_thread_num, max_task_queue_items);
serv_sock = socket(PF_INET, SOCK_STREAM, 0);
memset(&serv_addr, 0 , sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(port);
if(bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1){
error_message("bind() error");
}
if(listen(serv_sock, 5) == -1){
error_message("listen() error");
}
while(1){
clnt_addr_sz = sizeof(clnt_addr);
clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_sz);
if(clnt_sock == -1){
continue;
}
printf("clientIp: %s", inet_ntoa(clnt_addr.sin_addr));
addTask(pool, client_fun, (void*)&clnt_sock);
}
return 0;
}