linux线程池,信号量问题

lilistudy 2006-12-30 04:53:10
依照"Thread Pool C++ Game ProgrammingTutorial"(http://www.developers.net/intelisdshowcase/view/153)中的代码(Windows)
实现linux下的线程池,使用信号量同步。
gdb调试过程中发现信号量不能正常阻塞和唤醒。
环境:g++ 2.95.3 RedHat Enterprise Linux 3.
g++ -o PoolTest Pool.cpp PoolTest.cpp -lpthread
代码:
PoolConst.h
//////////////////////////
#ifndef SEM_CONST_H
#define SEM_CONST_H

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
using namespace std;

union semun {
int val;
struct semid_ds *buf;
unsigned short int *array;
struct seminfo *__buf;
};

#define SEM_MODE (IPC_CREAT|0660)

#define MAXQUEUE 15

#endif
//////////////////////////

Pool.h
////////////////////////
#ifndef POOL_LLS
#define POOL_LLS

#include "PoolConst.h"
//工作类
class CWorkThread
{
public:
unsigned virtual ThreadExecute();
virtual ~CWorkThread();
};

//线程池类
class Pool
{
public:
Pool(){};
Pool(int nMaxNumberThreads);

virtual ~Pool();
void DoWork();
void DestroyPool();
bool SubmitJob(CWorkThread* cWork);
bool GetWork(CWorkThread** cWork);
private:
long nWorkInProgress;
int m_nMaxNumThreads;
unsigned int m_Thrdaddr;

pthread_t m_threadhandles[MAXQUEUE];
CWorkThread* m_pQueue[MAXQUEUE];

static void * ThreadExecute(void *Param);

int m_nTopIndex;
int m_nBottomIndex;

int nEmptySlot;
int nWorkToDo;
int nExit;
pthread_mutex_t count_mutex;
int nProcNum;

bool Running;
};


#endif
///////////////////////

Pool.cpp
//////////////////////
// Pool.cpp: implementation of the Pool class.
//
//////////////////////////////////////////////////////////////////////

#include "Pool.h"
#include <iostream>
using namespace std;

//信号量等待
int semaphore_wait (int semid)
{
struct sembuf operations[1];
operations[0].sem_num = 0;
operations[0].sem_op = -1;
operations[0].sem_flg = SEM_UNDO;
return semop (semid, operations, 1);
}

//信号量唤醒
int semaphore_post (int semid)
{
struct sembuf operations[1];
operations[0].sem_num = 0;
operations[0].sem_op = 1;
operations[0].sem_flg = SEM_UNDO;
return semop (semid, operations, 1);
}


///CWorkThread 线程函数
unsigned int CWorkThread::ThreadExecute()
{
return 0;
}

CWorkThread::~CWorkThread()
{
}

Pool::Pool(int nMaxNumberThreads)
{
m_nMaxNumThreads = nMaxNumberThreads;
m_nMaxNumThreads = nMaxNumberThreads;
//获取标识空线程的信号量
nEmptySlot = semget(IPC_PRIVATE,1, SEM_MODE);
//获取标识工作线程的信号量
nWorkToDo = semget(IPC_PRIVATE,1, SEM_MODE);
//空线程信号量初始化 MAXQUEUE -1 (全部是空闲的)
if(semctl(nEmptySlot,0,SETVAL,MAXQUEUE -1 ) < 0)
{
cout << "semctl error"<<endl;
}
//空线程信号量初始化0 (没有工作线程)
if(semctl(nWorkToDo,0,SETVAL,0) < 0)
{
cout << "semctl error"<<endl;
}
pthread_mutex_init(&count_mutex, NULL);

int rc = 0;
for(int i=0;i<m_nMaxNumThreads;++i)
{
rc = pthread_create(&m_threadhandles[i], NULL , Pool::ThreadExecute,this);

}
for(int i = 0; i< MAXQUEUE; ++i)
{

m_pQueue[i] = NULL;
}
m_nTopIndex = 0;
m_nBottomIndex = 0;
nWorkInProgress=0;
nProcNum = 0;
Running = true;
}


Pool::~Pool()
{
if(semctl(nWorkToDo,IPC_RMID,0)<0)
{
cerr<<"semctl error!"<<endl;

}
if(semctl(nEmptySlot,IPC_RMID,0)<0)
{
cerr<<"semctl error!"<<endl;

}
}

void *Pool::ThreadExecute(void *Param){

((Pool*)Param)->DoWork();
return(0);
}

void Pool::DoWork()
{
CWorkThread* cWork;
while((GetWork(&cWork)))
{
try{
//用于结束线程
if(cWork == NULL)
{
break;
}
//执行工作代码
cWork->ThreadExecute();

pthread_mutex_lock(&count_mutex);
--nWorkInProgress;
delete cWork;
cWork=NULL;
pthread_mutex_unlock(&count_mutex);
}
catch(...)
{
cout << "Catch Exception!"<<endl;
}
}

}

//提交工作
bool Pool::SubmitJob(CWorkThread* cWork)
{

pthread_mutex_lock(&count_mutex);
++nWorkInProgress;
pthread_mutex_unlock(&count_mutex);
//wait nEmptySlot信号量,队列没有空闲位置则阻塞
semaphore_wait(nEmptySlot);
pthread_mutex_lock(&count_mutex);
//工作对象加入队列
m_pQueue[m_nTopIndex] = cWork;
m_nTopIndex = (++m_nTopIndex) % (MAXQUEUE);
//post nWorkToDo信号量
semaphore_post(nWorkToDo);
pthread_mutex_unlock(&count_mutex);

return(1);
}



bool Pool::GetWork(CWorkThread** cWork)
{
//wait nWorkToDo 信号量,没有工作则阻塞
semaphore_wait(nWorkToDo);
pthread_mutex_lock(&count_mutex);
//获取工作对象指针
CWorkThread* cWorker = m_pQueue[m_nBottomIndex];
*cWork = cWorker;
m_nBottomIndex = (++m_nBottomIndex) % (MAXQUEUE);
////post nEmptySlot信号量
semaphore_post(nEmptySlot);
pthread_mutex_unlock(&count_mutex);
return(1);
}


void Pool::DestroyPool(){

for (int i = 0; i < m_nMaxNumThreads; ++i)
pthread_join (m_threadhandles[i], NULL);
}

/////////////////////////

PoolTest.cpp
//////////////////////

#include "PoolConst.h"
#include "Pool.h"
using namespace std;

class CMyWork:public CWorkThread
{
public:
CMyWork(string a_strFileName)
{
strFileName = "test." + a_strFileName;
};
unsigned int ThreadExecute()
{
ofstream oFile(strFileName.c_str());
char * pBuf = new char [1024 * 1024];
memset(pBuf, 48, 1024 * 1024 - 1);
pBuf[1024 * 1024 - 1] = 0;
oFile << pBuf<<endl;
delete []pBuf;
pBuf = NULL;
}
private:
string strFileName;
};

int main(int argc, char *argv[])
{

vector<string> strVec;
strVec.push_back("a");strVec.push_back("b");
strVec.push_back("c");strVec.push_back("d");
strVec.push_back("e");strVec.push_back("f");
strVec.push_back("g");strVec.push_back("k");
strVec.push_back("h");strVec.push_back("l");
strVec.push_back("m");strVec.push_back("n");
strVec.push_back("o");strVec.push_back("p");
strVec.push_back("q");strVec.push_back("r");
strVec.push_back("s");strVec.push_back("t");
strVec.push_back("u");strVec.push_back("v");
vector<string>::iterator iterStr = strVec.begin();
Pool *myPool = new Pool(3);
for(iterStr; iterStr != strVec.end(); ++iterStr)
{

CMyWork *tWork = new CMyWork((*iterStr));
myPool->SubmitJob(tWork);
}
///提交NULL,线程结束
for(int i = 0; i < 3; ++i)
myPool->SubmitJob(NULL);

myPool->DestroyPool();
delete myPool;
myPool = NULL;
return 0;
}

///////////////////////////////////

PoolTest.cpp中代码生成test.* 形式的文件。
直接运行可以生成预期的所有文件,gdb调试环境下运行只能随机生成几个。

原因:
在Pool::SubmitJob(CWorkThread* cWork)方法提交工作对象之前,
Pool::GetWork(CWorkThread** cWork)方法执行了代码:
pthread_mutex_lock(&count_mutex);
//获取工作对象指针
CWorkThread* cWorker = m_pQueue[m_nBottomIndex];
*cWork = cWorker;
m_nBottomIndex = (++m_nBottomIndex) % (MAXQUEUE);
获取NULL指针,导致线程终止,也就是semaphore_wait(nWorkToDo),根本没有阻塞.
按照程序逻辑,Pool::SubmitJob(CWorkThread* cWork)执行
semaphore_post(nWorkToDo)之前semaphore_wait(nWorkToDo)应该阻塞.
请教各位代码有没有问题,gdb下信号量有什么特殊的行为吗?


www.cise.ufl.edu/~sahni/dsac
...全文
418 1 打赏 收藏 转发到动态 举报
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
lilistudy 2006-12-31
  • 打赏
  • 举报
回复
没人出手啊
是不是代码太复杂啦

23,125

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 应用程序开发区
社区管理员
  • 应用程序开发区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧