一个基于信号量的简易线程池

转载自:一个基于信号量的简易线程池


信号无需由同一个线程来获取和释放,因此信号可用于异步事件通知,如用于信号处理程序中。同时,由于信号包含状态,因此可以异步方式使用,而不用象条件变量那样要求获取互斥锁。但是,信号的效率不如互斥锁高。缺省情况下,如果有多个线程正在等待信号,则解除阻塞的顺序是不确定的。信号在使用前必须先初始化,但是信号没有属性。计数信号量与互斥锁一起使用时的功能几乎与条件变量一样强大。在许多情况下,使用计数信号量实现的代码比使用条件变量实现的代码更为简单。本文参考:1、Linux多线程编程-信号量的使用2、Linux C++ 一个线程池的简单实现


CThread.h

#ifndef CTHREAD_H_
#define CTHREAD_H_

#include <pthread.h>

class CThread {
private:
    pthread_t m_thread; //保持线程句柄
public:
    CThread(void* (*threadFuction)(void*),void* threadArgv);
    virtual ~CThread();

    void JoinThread();
};

#endif /* CTHREAD_H_ */

CThread.cpp

#include "CThread.h"

CThread::CThread(void* (*threadFuction)(void*),void* threadArgv) {

    // 初始化线程属性
    pthread_attr_t threadAttr;
    pthread_attr_init(&threadAttr);

    pthread_create(&m_thread, &threadAttr, threadFuction, threadArgv);
}

CThread::~CThread() {
    // TODO Auto-generated destructor stub
}


void CThread::JoinThread()
{
    // join
    pthread_join(m_thread, NULL);
}

CThreadManager.h

#ifndef CTHREADMANAGER_H_
#define CTHREADMANAGER_H_

#include <stdio.h>
#include <list>
#include <queue>
#include <semaphore.h>

#include "CThread.h"

using namespace std;

class CThreadManager {
    friend void* ManageFuction(void*);
private:
    sem_t m_sem;    // 信号量
    pthread_mutex_t m_mutex; // 互斥锁

    queue<int> m_queWork; // 工作队列
    list<CThread*> m_lstThread; // 线程list

    int (*m_threadFuction)(int); //函数指针,指向main函数传过来的线程执行函数


public:
    CThreadManager(int (*threadFuction)(int), int nMaxThreadCnt);
    virtual ~CThreadManager();

    int WaitSem();

    int PostSem();

    int LockMutex();

    int UnlockMutex();

    void PushWorkQue(int nWork);

    int PopWorkQue();

    int RunThreadFunction(int nWork);
};

#endif /* CTHREADMANAGER_H_ */

CThreadManager.cpp

#include "CThreadManager.h"

// 线程执行函数,它只是个壳子,处理信号量和互斥锁等,
// 最后调用main函数传过来的线程执行函数来实现业务处理
void* ManageFuction(void* argv)
{
    CThreadManager* pManager = (CThreadManager*)argv;

    // 进行无限循环(意味着线程是不销毁的,重复利用)
    while(true)
    {
        // 线程开启后,就在这里阻塞着,直到main函数设置了信号量
        pManager->WaitSem();
        printf("thread wakeup.\n");

        // 从工作队列中取出要处理的数
        pManager->LockMutex();
        int nWork = pManager->PopWorkQue();
        pManager->UnlockMutex();

        printf("call Count function.\n");
        pManager->RunThreadFunction(nWork);
    }

    return 0;
}


CThreadManager::CThreadManager(int (*threadFuction)(int), int nMaxThreadCnt) {

    sem_init(&m_sem, 0, 0);
    pthread_mutex_init(&m_mutex, NULL);

    m_threadFuction = threadFuction;

    for(int i=0; i<nMaxThreadCnt; i++)
    {
        CThread* pThread = new CThread(ManageFuction, this);
        printf("thread started.\n");
        m_lstThread.push_back(pThread);
    }
}

CThreadManager::~CThreadManager()
{
    sem_destroy(&m_sem);
    pthread_mutex_destroy(&m_mutex);

    list<CThread*>::iterator it;
    for(it=m_lstThread.begin(); it!=m_lstThread.end();it++)
    {
        (*it)->JoinThread();
    }
}

// 等待信号量
int CThreadManager::WaitSem()
{
    return sem_wait(&m_sem);
}

// 设置信号量
int CThreadManager::PostSem()
{
    return sem_post(&m_sem);
}

// 取得锁
int CThreadManager::LockMutex()
{
    int n= pthread_mutex_lock(&m_mutex);
    return n;
}

// 释放锁
int CThreadManager::UnlockMutex()
{
    return pthread_mutex_unlock(&m_mutex);
}

// 往工作队列里放要处理的数
void CThreadManager::PushWorkQue(int nWork)
{
    m_queWork.push(nWork);
}

// 从工作队列中取出要处理的数
int CThreadManager::PopWorkQue()
{
    int nWork = m_queWork.front();
    m_queWork.pop();

    return nWork;
}

// 执行main函数传过来的线程执行函数
int CThreadManager::RunThreadFunction(int nWork)
{
    return (*m_threadFuction)(nWork);
}

ThreadTest.cpp

#include <stdio.h>
#include <unistd.h>

#include "CThreadManager.h"

using namespace std;

// 线程要执行的函数
int Count(int nWork)
{
    int nResult = nWork * nWork;
    printf("count result is %d\n",nResult);

    return 0;
}

int main() {

    // 创建线程管理类的实例,把要执行的线程函数和最大线程数传进去
    CThreadManager* pManager = new CThreadManager(Count, 3);

    // 把要进行计算的数放到工作队列中
    pManager->PushWorkQue(5);
    pManager->PushWorkQue(20);

    // 设置信号量,唤醒线程
    pManager->PostSem();
    pManager->PostSem();

    // 等待子线程执行
    sleep(1);

    return 0;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容