📄 workthread.cpp
字号:
//WorkThread.cpp 线程的实现文件
//author:duanjigang
//desp:实现线程的功能函数
#include "CommHead.h"
#include <string>
using namespace std;
#include "WorkThread.h"
#include "LogHelper.h"
extern CLogHelper theLogger;
//工作线程的函数体
#ifdef __LINUX__
void*
#else
DWORD WINAPI
#endif
WorkThread(
#ifdef _WIN32
LPVOID
#else
void*
#endif
data);
//构造函数初始化相关变量
CWorkThread::CWorkThread()
{
m_pTask = NULL; //开始时任务为空
m_bShouldExit = false;//一开始肯定有用,所以无用标志位设置为false
InitLock(&m_Lock);//初始化线程资源锁
m_bFree = true; //设置空闲标志位
m_nID = -1;
}
CWorkThread::~CWorkThread()
{
}
//供外部对象调用,传递的参数实际上是一个CWorkThread对象的地址
int CWorkThread::Start(void* data)
{
string strError = "创建工作线程失败[CWorkThread::Start(void* data)]";
#ifdef _WIN32
DWORD dwThreadID;
if(CreateThread(NULL, 0, WorkThread, data, 0, &dwThreadID) == NULL)
{
theLogger.LogMessage(strError, true);
return 0;
}
#else
pthread_t thread;
if(pthread_create(&thread, NULL, WorkThread, data))
{
theLogger.LogMessage(strError, true);
return 0;
}
if(pthread_detach(thread))
{
return 0;
}
#endif
//strError = "工作线程:" + string(GetName()) + " 启动成功!";
//theLogger.LogMessage(strError, true);
return 1;
}
//工作线程函数体
#ifdef __LINUX__
void*
#else
DWORD WINAPI
#endif
WorkThread(
#ifdef _WIN32
LPVOID
#else
void*
#endif
data)
{
//因为传递进来的是一个线程对象的地址,所以我们要将它转化成
//指向线程对象的指针,这样才能调用线程的功能函数
CWorkThread* thread = (CWorkThread*)data;
if(!thread)
{
string str = "消息处理线程中无效的参数[WorkThread]";
theLogger.LogMessage(str, true);
return 0;
}
string str = string(thread->GetName()) + "启动[WorkThread]";
theLogger.LogMessage(str, true);
//循环检测,如果线程需要退出,则退出,否则执行run函数
while(1)
{
//使用这个接口,调度线程就能实现对
//工作线程的动态管理了,如果任务比较多
//则可以实时添加工作线程,如果空闲线程比较多,则可以动态的
//结束一些线程,也就是通过修改线程结束标志位的方法来实现
//每当执行完一个任务线程便会检测这个结束标志位,如果被设置了,则会
//退出,否则就继续执行
if(thread->ShouldExit())
{
string str = string(thread->GetName()) + "退出[WorkThread]";
theLogger.LogMessage(str, true);
return 0;
}
//执行任务
thread->Run();
//thread->SetExitFlag();
}
return 0;
}
//获取线程的名字,目前的做法是根据线程的ID构造
//比如线程ID为1的话,名字为 Thread_001,线程123的
//名字为Thread_123,只是为了打印格式上的好看,也可以根据
//线程名字生成专门的日志文件,为每个线程存储日志
char* CWorkThread::GetName()
{
static char szRet[128];
memset(szRet, 0, 128);
LockOn(&m_Lock);
sprintf(szRet, "%s", m_szName);
LockOff(&m_Lock);
return szRet;
}
//设置线程的ID,这个通过外部的函数来调用,所以设计为public类型
void CWorkThread::SetID(int nID)
{
memset(m_szName, 0, sizeof(m_szName));
sprintf(m_szName, "线程%03d", nID);
m_nID = nID;
}
//检测线程是否空闲,主要是调度线程来调用的
//因为它要为工作线程分配任务或者结束工作线程
//而且结束和分配任务都是在线程空闲的时候来进行的
//所以需要有一个函数能提供对线程状态的查询
bool CWorkThread::IsFree()
{
bool bRet = false;
LockOn(&m_Lock);
bRet = m_bFree;
LockOff(&m_Lock);
return bRet;
}
//线程运行函数,如果任务参数为空则直接退出
//否则执行任务对象直到结束
int CWorkThread::Run()
{
string str;
str = string(GetName()) + " 开始执行[CWorkThread::Run()]";
theLogger.LogMessage(str, true);
while(NULL == m_pTask)
{
string str = string(GetName()) + ": 参数为空[CWorkThread::Run()]";
SLEEP(5, 0);
theLogger.LogMessage(str, true);
}
//开始执行,直到结束条件满足
while(!m_pTask->MayEnd())
{
m_pTask->Execute();
}
//然后要修改线程的标志位,告诉外界它已经空闲了,以方便新的任务的分配
LockOn(&m_Lock);
m_bFree = true;
LockOff(&m_Lock);
m_pTask = NULL;
return 1;
}
//给线程分配任务,以继续线程的执行,这个函数是通过外界来调用的
bool CWorkThread::AssigTask(CTask *pTask)
{
if(NULL == pTask)
{
return false;
}
//修改锁和任务对象变量
LockOn(&m_Lock);
m_pTask = pTask;
m_bFree = false;
LockOff(&m_Lock);
return true;
}
//改变线程状态,如果为false则说明线程繁忙,如果为true则说明线程空闲
//主要是调度线程调用的,因为调度线程需要找到一个任务然后找出来一个空闲
//线程,然后把任务分配个这个空闲线程去执行
void CWorkThread::ChangeStatus(bool bNewStatus)
{
LockOn(&m_Lock);
m_bFree = bNewStatus;
LockOff(&m_Lock);
}
//这个是自身调用的,用在结束线程时使用
//如果这个线程需要结束则会直接退出
bool CWorkThread::ShouldExit()
{
bool bRet = false;
LockOn(&m_Lock);
bRet = m_bShouldExit;
LockOff(&m_Lock);
return bRet;
}
//获取线程的ID值,这几个关于线程ID的函数还有待商榷,确定是否要
//留下来
int CWorkThread::GetID()
{
int nRet = 0;
LockOn(&m_Lock);
nRet = m_nID;
LockOff(&m_Lock);
return nRet;
}
//设置退出标志位
void CWorkThread::SetExitFlag()
{
LockOn(&m_Lock);
m_bShouldExit = true;
LockOff(&m_Lock);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -