linux 下的C语言版本:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <pthread.h>
#include <unistd.h>
#define LL_INSERT(item,list) do{\
item->prev = NULL;\
item->next = list;\
if(list!=NULL) list->prev=item;\
list = item;\
}while(0)
#define LL_REMOVE(item,list) do {\
if(item->prev !=NULL) item->prev->next = item->next;\
if(item->next !=NULL) item->next->prev = item->prev;\
if(list == item) list = item->next;\
item->prev = item->next=NULL;\
}while(0)
//任务结构体
//具体的任务处理函数 用户传进来的参数(在必要的时候传给处理函数)
//因为任务需要放在队列里面,而且这个队列要很方便地插入和删除,所以使用链表比较好
struct NJOB {
void (*func)(void* args);
void *user_data;
struct NJOB* prev;
struct NJOB* next;
};
//执行任务的线程需要有一些属性辅助工作,所以封装一个worker结构体,存放辅助变量
//线程,线程退出标志 ,线程闲置标志,所属线程池的句柄
//同理这些线程要放在一个地方以便使用,考虑到可能动态的增加线程或者减少线程,所以
//也用一个链表存放
struct MANAGER;
struct NWORKER {
pthread_t th;
int terminate;
int idle;
struct MANAGER* pool;
struct NWORKER* prev;
struct NWORKER* next;
};
//线程队列和任务队列之间的调度,需要控制,所以加一个manager
//任务队列会被多个线程共享,是临界资源,需要加锁保护 mtx cond
struct MANAGER {
struct NJOB* jobs;
struct NWORKER* workers;
int numworkers;
pthread_mutex_t jobs_mtx;
pthread_cond_t jobs_cond;
};
typedef struct MANAGER nThreadPool;
static void* nThreadEntranceFunc(void* arg){
struct NWORKER* wkr = (struct NWORKER*)arg;
struct MANAGER* pool = wkr->pool;
while(1){
pthread_mutex_lock(&pool->jobs_mtx);
while(pool->jobs==NULL){
if(wkr->terminate>0)break;
wkr->idle = 1;
//等待被条件唤醒,一旦被唤醒就会开始抢锁,只有拿到锁pthread_cond_wait才会返回
pthread_cond_wait(&pool->jobs_cond,&pool->jobs_mtx);
}
if(wkr->terminate>0){
pthread_mutex_unlock(&pool->jobs_mtx);
break;
}
wkr->idle = 0;
struct NJOB* job = pool->jobs;
for(;job->next!=NULL;job=job->next);
LL_REMOVE(job,pool->jobs);
pthread_mutex_unlock(&pool->jobs_mtx);
job->func(job->user_data);
free(job->user_data);
free(job);
}
free(wkr);
return NULL;
}
int nThreadPoolInit(nThreadPool *pool, int numworkers){
if(numworkers<1) numworkers=1;
if(pool==NULL) return -1;
memset(pool,0,sizeof(nThreadPool));
pthread_cond_t blank_cond = PTHREAD_COND_INITIALIZER;
memcpy(&pool->jobs_cond,&blank_cond,sizeof(pthread_cond_t));
pthread_mutex_t blank_mutex = PTHREAD_MUTEX_INITIALIZER;
memcpy(&pool->jobs_mtx,&blank_mutex,sizeof(pthread_mutex_t));
int i=0;
for(;i<numworkers;i++){
struct NWORKER* wkr= (struct NWORKER*)malloc(sizeof(struct NWORKER));
if(wkr==NULL){
return -2;
}
memset(wkr,0,sizeof(struct NWORKER));
wkr->pool = pool;
int ret = pthread_create(&wkr->th,NULL,nThreadEntranceFunc,(void*)wkr);
if(ret!=0){
free(wkr);
return -3;
}
LL_INSERT(wkr,pool->workers);
pool->numworkers += 1;
}
return 0;
}
void nThreadPoolJobPush(nThreadPool *pool, struct NJOB* job){
pthread_mutex_lock(&pool->jobs_mtx);
LL_INSERT(job,pool->jobs);
pthread_mutex_unlock(&pool->jobs_mtx);
//如果cond_wait队列不为空,则至少将一个线程从cond_wait内部的阻塞状态唤醒
pthread_cond_signal(&pool->jobs_cond);
}
int nThreadPoolWorkerAdd(nThreadPool *pool,int num){
if(pool==NULL||pool->workers==NULL)
return -1;
for(int i=0;i<num;i++){
struct NWORKER* wkr= (struct NWORKER*)malloc(sizeof(struct NWORKER));
if(wkr==NULL){
return -2;
}
memset(wkr,0,sizeof(struct NWORKER));
wkr->pool = pool;
int ret = pthread_create(&wkr->th,NULL,nThreadEntranceFunc,wkr);
if(ret!=0){
free(wkr);
return -3;
}
LL_INSERT(wkr,pool->workers);
pool->numworkers+=1;
}
return pool->numworkers;
}
int nThreadPoolWorkerDrop(nThreadPool *pool,int num){
struct NWORKER* wkr = pool->workers;
int count=0;
pthread_mutex_lock(&pool->jobs_mtx);
for(;wkr!=NULL;wkr=wkr->next){
if(wkr->idle>0){
wkr->terminate=1;
count++;
}
if(count>=num)break;
}
pthread_mutex_unlock(&pool->jobs_mtx);
pthread_cond_broadcast(&pool->jobs_cond);
return count;
}
void nThreadPoolDestroy(nThreadPool *pool){
struct NWORKER* wkr=NULL;
for(wkr=pool->workers;wkr!=NULL;wkr=wkr->next)
wkr->terminate=1;
pthread_cond_broadcast(&pool->jobs_cond);
// make sure pool is terminate indeed.
sleep(1);
return;
}
//以下是模拟客户端程序
struct ArgCallback{
char name[15];
int age;
};
void callbacks(void* arg){
struct ArgCallback* para=(struct ArgCallback*)arg;
sleep(1);
printf("name=%s, age=%d\n",para->name,para->age);
}
void EXIT(int sig){
printf("外部信号:%d,主进程退出\n",sig);
exit(0);
}
int main(int argc, char* args[]){
nThreadPool Pool;
nThreadPoolInit(&Pool,50);
for(int i=0;i<500;i++){
struct NJOB* job=(struct NJOB*)malloc(sizeof(struct NJOB));
memset(job,0,sizeof(struct NJOB));
struct ArgCallback* arg=(struct ArgCallback*)malloc(sizeof(struct ArgCallback));
memset(arg,0,sizeof(struct ArgCallback));
sprintf(arg->name,"id_%d",i);
arg->age=i;
job->user_data=(void*)arg;
job->func=callbacks;
nThreadPoolJobPush(&Pool,job);
}
int isdestroyed=0;
while(1){
char c = getchar();
if(c=='d'){
nThreadPoolDestroy(&Pool);
isdestroyed = 1;
}
if(isdestroyed!=0&&c=='q')
break;
}
return 0;
// signal(SIGINT,EXIT); //ctrl+c signal
// signal(SIGTERM,EXIT);//kill -15 signal
// while(1){
// sleep(10);
// }
// return 0;
}
跨平台的c++版本:
#include <thread>
#include <mutex>
#include <condition_variable>
#include <list>
#include <cstring>
#include <iostream>
struct NJOB {
void (*func)(void* args);
void *user_data;
};
struct MANAGER;
struct NWORKER {
std::thread th;
int terminate;
int idle;
struct MANAGER* pool;
};
struct MANAGER {
std::list<NJOB*> jobs;
std::list<NWORKER*> workers;
int numworkers;
std::mutex jobs_mtx;
std::condition_variable jobs_cond;
};
typedef struct MANAGER nThreadPool;
static void* nThreadEntranceFunc(void* arg){
struct NWORKER* wkr = (struct NWORKER*)arg;
struct MANAGER* pool = wkr->pool;
while(1){
std::unique_lock<std::mutex> lock(pool->jobs_mtx);
while(pool->jobs.empty()){
if(wkr->terminate>0)break;
wkr->idle = 1;
//[1.解锁 2.当前线程入队cond_wait],wait函数会保证这两步一起执行,不被打断
//如果该线程从cond_wait中被移出,表明已经被唤醒,会进入抢锁状态,只有拿到锁后才会退出wait
pool->jobs_cond.wait(lock);
}
std::mutex* lPtr = lock.release();
if(wkr->terminate>0){
lPtr->unlock();
break;
}
wkr->idle = 0;
struct NJOB* job = pool->jobs.back();
pool->jobs.pop_back();
lPtr->unlock();
job->func(job->user_data);
free(job->user_data);
free(job);
}
free(wkr);
return NULL;
}
int nThreadPoolInit(nThreadPool *pool, int numworkers){
if(numworkers<1) numworkers=1;
if(pool==NULL) return -1;
int i=0;
for(;i<numworkers;i++){
struct NWORKER* wkr= (struct NWORKER*)malloc(sizeof(struct NWORKER));
if(wkr==NULL){
return -2;
}
memset(wkr,0,sizeof(struct NWORKER));
wkr->pool = pool;
std::thread* t = new(&(wkr->th)) std::thread(nThreadEntranceFunc,(void*)wkr);
//t->detach();
pool->workers.push_front(wkr);
pool->numworkers += 1;
}
return 0;
}
void nThreadPoolJobPush(nThreadPool *pool, struct NJOB* job){
{
std::unique_lock<std::mutex> lock(pool->jobs_mtx);
pool->jobs.push_front(job);
}
//如果cond_wait队列不为空,则至少将一个线程从cond_wait内部的阻塞状态唤醒
pool->jobs_cond.notify_one();
}
void nThreadPoolDestroy(nThreadPool *pool){
std::list<NWORKER*>::iterator it;
for(it=pool->workers.begin();it!=pool->workers.end();it++)
(*it)->terminate=1;
pool->jobs_cond.notify_all();
// make sure pool is terminate in real.
std::this_thread::sleep_for(std::chrono::milliseconds(500));
return;
}
int nThreadPoolWorkerAdd(nThreadPool *pool,int num){
if(pool==NULL)
return -1;
for(int i=0;i<num;i++){
struct NWORKER* wkr= (struct NWORKER*)malloc(sizeof(struct NWORKER));
if(wkr==NULL){
return -2;
}
memset(wkr,0,sizeof(struct NWORKER));
wkr->pool = pool;
std::thread* t = new(&(wkr->th)) std::thread(nThreadEntranceFunc,(void*)wkr);
//t->detach();
pool->workers.push_front(wkr);
pool->numworkers+=1;
}
return pool->numworkers;
}
int nThreadPoolWorkerDrop(nThreadPool *pool,int num){
int count=0;
pool->jobs_mtx.lock();
std::list<NWORKER*>::iterator it;
for(it=pool->workers.begin();it!=pool->workers.end();it++){
if((*it)->idle>0){
(*it)->terminate=1;
count++;
}
if(count>=num)break;
}
pool->jobs_mtx.unlock();
pool->jobs_cond.notify_all();
return count;
}
struct ArgCallback{
char name[15];
int age;
};
void callbacks(void* arg){
struct ArgCallback* para=(struct ArgCallback*)arg;
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
printf("name=%s, age=%d\n",para->name,para->age);
}
void EXIT(int sig){
printf("外部信号:%d,主进程退出\n",sig);
exit(0);
}
int main(int argc, char* args[]){
nThreadPool* Pool=new nThreadPool;
nThreadPoolInit(Pool,50);
for(int i=0;i<500;i++){
struct NJOB* job=(struct NJOB*)malloc(sizeof(struct NJOB));
memset(job,0,sizeof(struct NJOB));
struct ArgCallback* arg=(struct ArgCallback*)malloc(sizeof(struct ArgCallback));
memset(arg,0,sizeof(struct ArgCallback));
sprintf(arg->name,"cpp_id_%d",i);
arg->age=i;
job->user_data=(void*)arg;
job->func=callbacks;
nThreadPoolJobPush(Pool,job);
}
int isdestroyed=0;
while(1){
char c = getchar();
if(c=='d'){
nThreadPoolDestroy(Pool);
isdestroyed = 1;
}
if(isdestroyed!=0&&c=='q')
break;
}
delete Pool;
return 0;
}
可以考虑做成sdk以便调用。。。
------------------------------------------------补充一个内存池----------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
enum
{
BLOCKTYPE_START = 0,
BLOCKTYPE_64 = BLOCKTYPE_START,
BLOCKTYPE_128,
BLOCKTYPE_256,
BLOCKTYPE_512,
BLOCKTYPE_1024,
BLOCKTYPE_2048,
BLOCKTYPE_4096,
BLOCKTYPE_COUNT
};
const uint64_t pagesize = 4096;
const uint64_t pageconf[][3] = { { 64, 0xFFFFFFFFFFFFFFFF, 64 },
{ 128, 0xFFFFFFFF, 32 }, { 256, 0xFFFF, 16 }, { 512, 0xFF, 8 },
{ 1024, 0xF, 4 }, { 2048, 0x3, 2 }, { 4096, 0x1, 1 } };
struct zv_block_s{ uint64_t sizetype; uint64_t used; void* mem; };
struct zv_slab_s{
int blockcount;
struct zv_block_s* empty;
struct zv_block_s* end;
struct zv_block_s* slot[BLOCKTYPE_COUNT];
void* pages;
struct zv_block_s blocks[0];
};
struct zv_slab_s* zv_slab_init(void* pool, uint64_t size)
{
struct zv_slab_s* s = (struct zv_slab_s*)pool;
s->empty = s->blocks;
uint64_t block_size = pagesize + sizeof(struct zv_block_s);
s->blockcount = (size - sizeof(struct zv_slab_s)) / block_size;
s->pages = (char*)pool + sizeof(struct zv_slab_s) + sizeof(struct zv_block_s)*s->blockcount;
s->empty = s->blocks;
s->end = s->blocks + s->blockcount;
int slot_id = -1;
int slot_group_count = s->blockcount / BLOCKTYPE_COUNT;
int slot_extra_count = s->blockcount % BLOCKTYPE_COUNT;
slot_group_count = slot_group_count > 0 ? slot_group_count : 1;
for (int i = 0; i<s->blockcount; i++)
{
if((i-slot_extra_count)<0)
{
s->blocks[i].sizetype = pageconf[0][0];
s->blocks[i].used = 0;
s->blocks[i].mem = (char*)s->pages + i*pagesize;
continue;
}
if ((i-slot_extra_count) % slot_group_count == 0) slot_id++;
if (slot_id >= BLOCKTYPE_COUNT) slot_id = 0;
s->blocks[i].sizetype = pageconf[0][0] * (1 << slot_id);
s->blocks[i].used = 0;
s->blocks[i].mem = (char*)s->pages + i*pagesize;
}
for (int i = 0; i<BLOCKTYPE_COUNT; i++)
{
if(i>=1)
s->slot[i] = s->blocks + slot_extra_count + i*slot_group_count;
else
s->slot[i] = s->blocks + i*slot_group_count;
}
return s;
}
void* zv_slab_malloc(struct zv_slab_s* s, uint64_t sz)
{
if (s == NULL || sz>pagesize)return NULL;
size_t typ = BLOCKTYPE_START;
while (sz>pageconf[typ][0])typ++;
struct zv_block_s* block = s->slot[typ];
int slot_group_count = s->blockcount / BLOCKTYPE_COUNT;
if(typ == BLOCKTYPE_64) slot_group_count += s->blockcount % BLOCKTYPE_COUNT;
for (; slot_group_count>0 && (block->used - pageconf[typ][1]) == 0; slot_group_count--)
block++;
if(slot_group_count<=0)return NULL;
int64_t i = 0, n = pageconf[typ][2];
while (i<n && (block->used&(0x1 << i)))i++;
block->used |= (0x1 << i);
void* ptr = ((char*)block->mem) + i*pageconf[typ][0];
return ptr;
}
void zv_slab_free(struct zv_slab_s* s, void* ptr)
{
int64_t page = ((char*)ptr - s->pages) / pagesize;
struct zv_block_s* b = &(s->blocks[page]);
int64_t idx = ((char*)ptr - b->mem) / b->sizetype;
b->used ^= (0x1 << idx);
return;
}
int main(int argc, char* argv[])
{
uint64_t psize = 2 * 1024 * 1024;
void* pool = malloc(psize);
if (pool == NULL)return - 1;
struct zv_slab_s* slab = zv_slab_init(pool, psize);
void* p = zv_slab_malloc(slab, 176);
void* p1 = zv_slab_malloc(slab, 183);
zv_slab_free(slab, p);
free(pool);
}
c++版本的内存池
#include <list>
#include <mutex>
#define DEFAULT_NEW_SIZE 10240
class MemoryPoolInternal
{
public:
MemoryPoolInternal();
~MemoryPoolInternal();
void* allocate(size_t size);
void deallocate(void* ptr);
private:
struct Unit
{
bool is_free;
Unit* prev;
Unit* next;
size_t size;
char data[0];
};
using Block = Unit;
std::list<Block*> m_blocks;
std::mutex m_mutex;
};
MemoryPoolInternal::MemoryPoolInternal()
{}
MemoryPoolInternal::~MemoryPoolInternal()
{
for (auto& block : m_blocks)
{
if (nullptr != block)
{
delete[] (char*) block;
block = nullptr;
}
}
}
void* MemoryPoolInternal::allocate(size_t size)
{
std::lock_guard<std::mutex> lock(m_mutex);
Unit* item = nullptr;
for (auto block : m_blocks)
{
for (item = (Unit*)block; nullptr != item; item = item->next)
{
if (item->is_free && item->size >= size)
{
break;
}
}
if (nullptr != item)
{
break;
}
}
if (nullptr == item)
{
auto data_size = size>DEFAULT_NEW_SIZE?size: DEFAULT_NEW_SIZE;
auto block_size = sizeof(Unit) + data_size;
Block* new_block = (Block*)new(std::nothrow) char[block_size];
if (new_block == nullptr)
{
return nullptr;
}
m_blocks.push_back(new_block);
item = (Unit*)new_block;
item->next = nullptr;
item->prev = nullptr;
item->size = data_size;
}
item->is_free = false;
if (item->size - size > sizeof(Unit))
{
Unit* new_item = reinterpret_cast<Unit*>(item->data + size);
new_item->is_free = true;
new_item->size = item->size - size - sizeof(Unit);
item->size = size;
new_item->next = item->next;
if (item->next)
item->next->prev = new_item;
new_item->prev = item;
}
memset(item->data, 0x00, item->size);
return item->data;
}
void MemoryPoolInternal::deallocate(void* ptr)
{
std::lock_guard<std::mutex> lock(m_mutex);
Unit* item = (Unit*)((char*)ptr - sizeof(Unit));
item->is_free = true;
bool block_free = true;
while (item->next && item->next->is_free)//检查后面一片连续空间,是否可以合并
{
item->size += sizeof(Unit) + item->next->size;
item->next = item->next->next;
if (item->next)
item->next->prev = item;
}
if (nullptr != item->next)
{
block_free = false;
}
while (item->prev && item->prev->is_free)//检查前面一片空间,是否可以合并
{
item->prev->size += sizeof(Unit) + item->size;
item->prev->next = item->next;
if (item->next != nullptr)
{
item->next->prev = item->prev;
}
item = item->prev;
}
if (nullptr != item->prev)
{
block_free = false;
}
if (block_free)
{
Block* block = (Block*)item;
if (m_blocks.size() > 1)//释放多余的内存,至少保留一个block
{
m_blocks.remove(block);
delete[] (char*)block;
}
}
}
static MemoryPoolInternal g_mmpoll;
extern "C" __declspec(dllexport) void* __stdcall allocate(size_t size)
{
return g_mmpoll.allocate(size);
}
extern "C" __declspec(dllexport) void __stdcall deallocate(void* ptr)
{
return g_mmpoll.deallocate(ptr);
}
注意:从内存池申请到的指针,其所在位置附近存放了用于维护内存池的元数据,一旦发生写越界,就会导致元数据损坏,造成不可预测的后果。因此,需要十分注意