muduo源码解析15-thread类

thread类:

//namespace mymuduo 
class thread
{
};

//namespace mymuduo::detail
struct ThreadData
{
};

作用:

两个重要的类mymuduo::thread和mymuduo::detail::ThreadData
thread类实现了对于线程的封装,内部提供了start(),join(),和一些返回线程状态信息的方法
ThreadData类封装了线程数据信息,包括线程名字,ID,线程函数,倒计时计数信息.这个类主要用于
pthread_create()函数中作为线程传参而使用的.

下面说一下创建线程并且执行的完成的步骤:
thread类在构造函数中完成线程信息的初始化,即初始化类内部成员变量
调用start()启动线程,实际上用pthread_create()启动线程,传入ThreadData对象指针作为线程
传参,注意该处pthread_create()并不是直接调用m_func线程函数,而是间接调用detail::startThread
函数,之后在startThread函数中获取ThreadData信息,并执行ThreadData::runInThread函数完成
具体的线程函数m_func的调用

简略步骤:
thread::thread() //设置线程信息成员变量
thread::start() //pthread_create,调用detail::startThread(),传参ThreadData
detail::startThread() //内部调用ThreadData::runInThread(),完成m_func线程函数调用

还需要注意之前的currentthread名字空间中有的函数仅是声明而未实现,例如currentthread::cacheTid()
在这里进行了实现,并且对currentthread中的四个全局变量(线程ID,名字等)提供了相应的设置函数.

ThreadData成员变量:

public:
    typedef thread::ThreadFunc ThreadFunc;
    ThreadFunc m_func;          //线程函数
    string m_name;              //线程名字
    pid_t* m_tid;               //线程ID
    countdownlatch* m_latch;    //倒计时计数

用于保存基本线程信息

ThreadData成员函数:

    //构造函数初始化
    ThreadData(ThreadFunc func,const string& name,pid_t* tid,countdownlatch* latch)
        :m_func(std::move(func)),m_name(name),m_tid(tid),m_latch(latch)
    {

    }

    //运行线程
    void runInThread()
    {
        //设置类成员变量
        *m_tid=currentthread::tid();
        m_tid=NULL;
        m_latch->countDown();
        m_latch=NULL;

        //设置线程名字
        currentthread::t_threadName=m_name.empty()?"muduoThread":m_name.data();
        ::prctl(PR_SET_NAME,currentthread::t_threadName);
        try {
            m_func();           //具体的运行函数
            currentthread::t_threadName="finished"; //执行结束
        } catch (const mymuduo::exception& ex) {
            currentthread::t_threadName = "crashed";
            fprintf(stderr, "exception caught in Thread %s\n", m_name.c_str());
            fprintf(stderr, "reason: %s\n", ex.what());
            fprintf(stderr, "stack trace: %s\n", ex.stackTree());
            abort();
        }catch(const std::exception& ex)
        {
            currentthread::t_threadName = "crashed";
            fprintf(stderr, "exception caught in Thread %s\n", m_name.c_str());
            fprintf(stderr, "reason: %s\n", ex.what());
            abort();
        }catch(...)
        {
            currentthread::t_threadName="crashed";
            fprintf(stderr,"unknown exception caught in Thread %s\n",
                    m_name.c_str());
            throw;
        }
    }

thread成员变量:

private:
    bool m_started;             //线程是否启动
    bool m_joined;              //是否被join回收
    pthread_t m_pthreadId;      //线程ID
    pid_t m_tid;                //进程ID
    ThreadFunc m_func;          //线程函数
    string m_name;              //线程名字
    countdownlatch m_latch;     //倒计时计数

    static atomicInt32 m_numCreated;    //本进程创建的线程数量

thread成员函数:

public:
    typedef std::function<void()> ThreadFunc;
    //构造函数,调用setDefaultName,用于各种成员传入参数
    explicit thread(ThreadFunc,const string& name=string());
    //析构函数负责把线程detach让其自己销毁
    ~thread();

    void start();

    int join();

    //返回内部成员线程是否启动,线程ID,线程名字
    bool started() const {return m_started;}
    pid_t tid() const {return m_tid;}
    const string& name() const {return m_name;}

    //返回本进程创建的线程数目
    static int numCreated(){return m_numCreated.get();}

private:

    //设置m_name
    void setDefaultName();

 

thread.h:

#ifndef THREAD_H
#define THREAD_H

#include"base/atomic.h"
#include"base/countdownlatch.h"
#include"base/types.h"

#include<functional>
#include<memory>
#include<pthread.h>

namespace mymuduo{

class thread
{
public:
    typedef std::function<void()> ThreadFunc;
    //构造函数,调用setDefaultName,用于各种成员传入参数
    explicit thread(ThreadFunc,const string& name=string());
    //析构函数负责把线程detach让其自己销毁
    ~thread();

    void start();

    int join();

    //返回内部成员线程是否启动,线程ID,线程名字
    bool started() const {return m_started;}
    pid_t tid() const {return m_tid;}
    const string& name() const {return m_name;}

    //返回本进程创建的线程数目
    static int numCreated(){return m_numCreated.get();}

private:

    //设置m_name
    void setDefaultName();

    bool m_started;             //线程是否启动
    bool m_joined;              //是否被join回收
    pthread_t m_pthreadId;      //线程ID
    pid_t m_tid;                //进程ID
    ThreadFunc m_func;          //线程函数
    string m_name;              //线程名字
    countdownlatch m_latch;     //倒计时计数

    static atomicInt32 m_numCreated;    //本进程创建的线程数量

};

}


#endif // THREAD_H

thread.cpp:

#include "thread.h"

#include"base/currentthread.h"
#include"base/exception.h"
#include"base/exception.h"
#include"base/logging.h"

#include<type_traits>
#include<errno.h>
#include<stdio.h>
#include<unistd.h>
#include<sys/prctl.h>
#include<sys/syscall.h>
#include<sys/types.h>
#include<linux/unistd.h>

namespace mymuduo {

namespace detail{

//得到唯一的线程ID
pid_t gettid()
{
    return static_cast<pid_t>(::syscall((SYS_gettid)));
}
//currentthread中以前定义了四个__thread变量,用来描述线程信息,在这里进行设置
void afterFork()
{
    currentthread::t_cachedTid=0;
    currentthread::t_threadName="main";
    currentthread::tid();
}

//线程初始化函数,负责初始化线程信息
class ThreadNNameInitializer
{
public:
    ThreadNNameInitializer()
    {
        currentthread::t_threadName="main";
        currentthread::tid();
        pthread_atfork(NULL,NULL,&afterFork);
    }
};
//全局线程初始化对象,完成currentthread中线程全局变量的设置
ThreadNNameInitializer init;
//线程数据类,
struct ThreadData
{
    typedef thread::ThreadFunc ThreadFunc;
    ThreadFunc m_func;          //线程函数
    string m_name;              //线程名字
    pid_t* m_tid;               //线程ID
    countdownlatch* m_latch;    //倒计时计数

    //构造函数初始化
    ThreadData(ThreadFunc func,const string& name,pid_t* tid,countdownlatch* latch)
        :m_func(std::move(func)),m_name(name),m_tid(tid),m_latch(latch)
    {

    }

    //运行线程
    void runInThread()
    {
        //设置类成员变量
        *m_tid=currentthread::tid();
        m_tid=NULL;
        m_latch->countDown();
        m_latch=NULL;

        //设置线程名字
        currentthread::t_threadName=m_name.empty()?"muduoThread":m_name.data();
        ::prctl(PR_SET_NAME,currentthread::t_threadName);
        try {
            m_func();           //具体的运行函数
            currentthread::t_threadName="finished"; //执行结束
        } catch (const mymuduo::exception& ex) {
            currentthread::t_threadName = "crashed";
            fprintf(stderr, "exception caught in Thread %s\n", m_name.c_str());
            fprintf(stderr, "reason: %s\n", ex.what());
            fprintf(stderr, "stack trace: %s\n", ex.stackTree());
            abort();
        }catch(const std::exception& ex)
        {
            currentthread::t_threadName = "crashed";
            fprintf(stderr, "exception caught in Thread %s\n", m_name.c_str());
            fprintf(stderr, "reason: %s\n", ex.what());
            abort();
        }catch(...)
        {
            currentthread::t_threadName="crashed";
            fprintf(stderr,"unknown exception caught in Thread %s\n",
                    m_name.c_str());
            throw;
        }
    }
};

//从属于detail命名空间,使用ThreadData类创建并且启动线程
void* startThread(void* obj)
{
  ThreadData* data = static_cast<ThreadData*>(obj);
  data->runInThread();
  delete data;
  return NULL;
}

}//namespace detail

//之前currentthread中没有定义此方法,因此在这里进行定义
void currentthread::cacheTid()
{
  //设置 __thread修饰的 currentthread::线程ID,线程名字长度
  if (t_cachedTid == 0)
  {
    t_cachedTid = detail::gettid();
    t_tidStringLength = snprintf(t_tidString, sizeof t_tidString, "%5d ", t_cachedTid);
  }
}

//判断是否是主线程,进程ID是否是线程ID
bool currentthread::isMainThread()
{
  return tid() == ::getpid();
}

//线程挂起一段时间
void currentthread::sleepUsec(int64_t usec)
{
  struct timespec ts = { 0, 0 };
  ts.tv_sec = static_cast<time_t>(usec / timestamp::microSecInSec);
  ts.tv_nsec = static_cast<long>(usec % timestamp::microSecInSec * 1000);
  ::nanosleep(&ts, NULL);   //挂起当前线程
}

//thread类中的static 变量,表示当前进程创建的线程数目
atomicInt32 thread::m_numCreated;

//构造函数,初始化线程信息,是否启动,回收,线程ID,进程ID,执行函数,线程名字,倒计时计数
thread::thread(ThreadFunc func, const string& n)
  : m_started(false),
    m_joined(false),
    m_pthreadId(0),
    m_tid(0),
    m_func(std::move(func)),
    m_name(n),
    m_latch(1)
{
  setDefaultName();     //构造时确定名字
}

//析构时把线程detach,不用父进程回收子线程
thread::~thread()
{
  if (m_started && !m_joined)
  {
    pthread_detach(m_pthreadId);
  }
}

//设置线程名字,格式为 "Thread%d"
void thread::setDefaultName()
{
    //当前进程的线程数目++
  int num = m_numCreated.incrementAndGet();
  if (m_name.empty())
  {
    char buf[32];
    snprintf(buf, sizeof buf, "Thread%d", num);
    m_name = buf;
  }
}

//启动,利用pthread_create()创建一个线程去执行detail::startThread函数
//把ThreadData指针作为参数传入,在startThread函数中执行ThreadData::runInThread
//完成具体的线程函数调用
void thread::start()
{
  assert(!m_started);
  m_started = true;
  // FIXME: move(func_)
  detail::ThreadData* data = new detail::ThreadData(m_func, m_name, &m_tid, &m_latch);
  if (pthread_create(&m_pthreadId, NULL, &detail::startThread, data))
  {
      //线程创建失败
    m_started = false;
    delete data; // or no delete?
    LOG_SYSFATAL << "Failed in pthread_create";
  }
  else
  {
      //线程创建成功
    m_latch.wait();
    assert(m_tid > 0);
  }
}

//回收子线程
int thread::join()
{
  assert(m_started);
  assert(!m_joined);
  m_joined = true;
  return pthread_join(m_pthreadId, NULL);
}
}

测试:

#include"base/thread.h"
#include<iostream>

#define __STDC_FORMAT_MACROS
#include <inttypes.h>

using namespace std;

void workerthread1()
{
    //线程函数内部调用currentthread提供的全局变量/函数来获取线程信息
    mymuduo::currentthread::sleepUsec(1000000);
    std::cout<<mymuduo::currentthread::name()<<" ";
    std::cout<<mymuduo::currentthread::tid()<<std::endl;
}

void workerthread2()
{
    mymuduo::currentthread::sleepUsec(1000000);
    std::cout<<mymuduo::currentthread::name()<<" ";
    std::cout<<mymuduo::currentthread::tid()<<std::endl;
}

mymuduo::thread::ThreadFunc tfunc;

int main()
{

    tfunc=workerthread1;
    mymuduo::thread t1(tfunc,"I'm thread1");
    t1.start();
    //通过thread提供的方法来获取线程信息
    std::cout<<t1.name()<<" "<<t1.tid()<<std::endl;

    tfunc=workerthread2;
    mymuduo::thread t2(tfunc,"I'm thread2");
    t2.start();
    //通过thread提供的方法来获取线程信息
    std::cout<<t2.name()<<" "<<t2.tid()<<std::endl;

    std::cout<<"当前创建的线程数目: "<<mymuduo::thread::numCreated()<<std::endl;
    t1.join();t2.join();

    std::cout<<"over...\n";
}

打印结果:

I'm thread1 91612
I'm thread2 91613
当前创建的线程数目: 2
I'm thread1 91612
I'm thread2 91613
over...

 

posted @ 2020-08-26 02:14  WoodInEast  阅读(328)  评论(0编辑  收藏  举报