c++ 线程类

        在 C++11 发布前,C++语言本身并不支持线程,而是通过 pthread 库来进行支持的,C++11发布后,其语言本身已经支持了线程,且是通过线程类的方式进行提供,使用方法可能参考此篇文章:c++11线程类 。现在C++11及之后版本已经提供了线程类来使用线程,但我们在编译的时候还是需要添加 -lpthread 链接(也许其线程类实现还是得依赖 pthread 库吧,没看过源码还不清楚),那如果不使用c++提供的线程类,我们在实际项目中是如何封装的线程类呢?

        以下代码先以 muduo 库里的线程类进行一下讲解,看它是如何封装线程类的,如:

#ifndef __UNI_THREAD_H__
#define __UNI_THREAD_H__

#include <boost/function.hpp>
#include <boost/noncopyable.hpp>
#include <pthread.h>


class CThread: public boost::noncopyable
{
public:
    typedef boost::function0<void> threadProc;
    explicit CThread(const threadProc& proc, std::string threaName);
    ~CThread();

    void createThread();

    bool started()const 
    {
        return mStarted;
    }

    pid_t tid() const
    {
        return mTid;
    }

    const std::string& name()const
    {
        return mName;
    }

    int join();
private:
    static void* startThread(void* arg);

    void runInThread();
private:
    bool       mStarted;
    pthread_t  mPthreadId;
    pid_t      mTid;
    threadProc funcProc;
    std::string     mName;
};

#endif

 这是一个线程类的声明,我们看到此类构造函数里就可以绑定要执行的线程函数。它的实现是这样的:

#include <assert.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <errno.h>
#include "Thread.h"
#include "CurrentThread.h"

namespace detail
{
    pid_t gettid()
    {
        return static_cast<pid_t>(::syscall(SYS_gettid));
    }
};


/*****************************
 * namespace CurrentThread
 * **************************/
namespace CurrentThread
{
    __thread int tCachedTid = 0;
    __thread char tTidString[32];
    __thread const char *tThreadName = "unknow";

};

void CurrentThread::cacheTid()
{
    ///第一次调用时会调用系统函数
    if(tCachedTid == 0)
    {
        tCachedTid = detail::gettid();
        snprintf(tTidString, sizeof(tTidString), "%5d ", tCachedTid);
    }
}

bool CurrentThread::isMainThread()
{
    return tid() == ::getpid();
}


/*****************************
 * CThread
 * **************************/
CThread::CThread(const threadProc& proc, std::string threaName):
mStarted(false),
mPthreadId(-1),
funcProc(proc),
mName(threaName)
{

}

CThread::~CThread()
{

}

void CThread::createThread()
{
    assert(!mStarted);
    mStarted = true;

    errno = pthread_create(&mPthreadId, NULL, startThread, this);
    if(errno < 0)
    {

    }
}

void* CThread::startThread(void* arg)
{
    CThread *thread = static_cast<CThread*>(arg);
    thread->runInThread();
    return nullptr;
}

void CThread::runInThread()
{
    mTid = CurrentThread::tid();
    if(funcProc)
    {
        funcProc();
    }
}

int CThread::join()
{
    assert(mStarted);
    return pthread_join(mPthreadId, nullptr);
}

可以看到在 createThread() 成员函数里调用了 pthread_create() 进行线程的创建,而且线程函数是此类的一个 static 函数 startThread(void* arg),为什么是 static 类型函数呢?因为函数 pthread_create() 的第 3 个参数是一个函数指针,且是 C 语言类型的函数指针,这里无法传入类的成员函数。实际工作中遇到的是另外一种实现方法,后面会有介绍。所以使用时,只要定义一个CThread 对象,然后调用 createThread() 即可,如:

在 调用 CAsyncLogging::start() 后,线程即刻创建起来,且执行线程函数 threadProc()。

实际工作中遇到线程类是这样的,列举片段:

// 线程类的声明
class CThread
{
    ///其他成员函数
    
    bool createThread();

	/// 线程执行体,是一个纯虚函数,派生的线程类中必须实现此函数,实现各自的行为。
	virtual void threadProc() = 0;    
}

这里最重要的是声明了一个纯虚函数,说明这个类是一个抽象类,只能用作基类。它也有一个 public 成员函数 createThread(),通过此函数创建线程,但这里比上面那个 createThread() 复杂一点,它里面会设置线程的属性、调度策略、线程优先级、线程栈大小等。 

ret = pthread_create(&mInternal->mHandle, &attr, threadBody, (void *)mInternal);

 它的线程函数也是一个全局函数,最后一个是一个内部的对象,保存着这个线程的相关信息。在线程函数里首先会把这个参数强转成指定类型,然后再进行调用。

pInternal->mOwner->threadProc();

而这个mOwner 就是在CThread 的构造函数里被赋为了 this,就是CThread对象,派生类只要实现 virtual void threadProc(),然后调用 createThread() 后就可以调用到自己的 threadProc() 函数了,这里用到的就是类的虚函数特性了。使用起来也很方便:

#include "Thread.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

class CMyThread: public CThread 
{
public:
    CMyThread();
    ~CMyThread();

    virtual void threadProc();
};

CMyThread::CMyThread(): CThread("myThread")
{

}

CMyThread::~CMyThread()
{

}

void CMyThread::threadProc()
{
    int count = 5;
    while(count--)
    {
        sleep(1);
        printf("in CMyThread\n");
    }
}

int main()
{
    CMyThread *myThread = new CMyThread();
    myThread->createThread();

    sleep(7);
    return 0;
}

派生类里只要实现 threadProc() 即可,运行结果如:

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值