Muduo源码Base篇

Muduo源码Base

Thread类

class Thread : noncopyable
{
 public:
  typedef std::function<void ()> ThreadFunc;

  explicit Thread(ThreadFunc, const string& name = string());
  // FIXME: make it movable in C++11
  ~Thread();

  void start();
  int join(); // return pthread_join()

  bool started() const { return started_; }
  // pthread_t pthreadId() const { return pthreadId_; }
  pid_t tid() const { return tid_; }
  const string& name() const { return name_; }

  static int numCreated() { return numCreated_.get(); }

 private:
  void setDefaultName();

  bool       started_;
  bool       joined_;
  pthread_t  pthreadId_;
  pid_t      tid_;
  ThreadFunc func_;
  string     name_;
  CountDownLatch latch_;

  static AtomicInt32 numCreated_;
};

在看Thread类之前先看CountDownLatch类
这是一个倒计时 类似于linux下提供的屏障
一个简单的例子 主线程等待十个副线程完成操作再运行

#include<iostream>
#include<thread>
#include<vector>

#include"CountDownLatch.h"
using namespace std;

using namespace mynamespace; 


CountDownLatch latch(10);

void threadfunc(int  i){

        
    printf("my thread id is %d\n",
            i);
    latch.CountDown(); 
    
}
int main(){

    vector<thread> vec;

    for(int i=0;i<10;++i){
        vec.emplace_back(thread(threadfunc,i));
    
    }
    latch.Wait();
    printf("main thread is running\n");

    for(auto &it:vec)
    {
        it.join();
    }
}

在这里插入图片描述

Atomic类 
主要是以下三个函数
__sync_val_compare_and_swap
__sync_fetch_and_add
__sync_lock_test_and_set

```cpp
type __sync_fetch_and_add(type *ptr, type value, ...); // m+n
type __sync_fetch_and_sub(type *ptr, type value, ...); // m-n
type __sync_fetch_and_or(type *ptr, type value, ...);  // m|n
type __sync_fetch_and_and(type *ptr, type value, ...); // m&n
type __sync_fetch_and_xor(type *ptr, type value, ...); // m^n
type __sync_fetch_and_nand(type *ptr, type value, ...); // (~m)&n
/* 对应的伪代码 */
{ tmp = *ptr; *ptr op= value; return tmp; }
{ tmp = *ptr; *ptr = (~tmp) & value; return tmp; }   // nand
type __sync_add_and_fetch(type *ptr, type value, ...); // m+n
type __sync_sub_and_fetch(type *ptr, type value, ...); // m-n
type __sync_or_and_fetch(type *ptr, type value, ...); // m|n
type __sync_and_and_fetch(type *ptr, type value, ...); // m&n
type __sync_xor_and_fetch(type *ptr, type value, ...); // m^n
type __sync_nand_and_fetch(type *ptr, type value, ...); // (~m)&n
/* 对应的伪代码 */
{ *ptr op= value; return *ptr; }
{ *ptr = (~*ptr) & value; return *ptr; } // nand
bool __sync_bool_compare_and_swap (type *ptr, type oldval, type newval, ...);
type __sync_val_compare_and_swap (type *ptr, type oldval, type newval, ...);
/* 对应的伪代码 */
{ if (*ptr == oldval) { *ptr = newval; return true; } else { return false; } }
{ if (*ptr == oldval) { *ptr = newval; } return oldval; }

GNU bool
https://gcc.gnu.org/onlinedocs/gcc-4.1.1/gcc/Atomic-Builtins.html
Thread类
构造函数以及初始化

Thread::Thread(ThreadFunc func, const string& n)
  : started_(false),
    joined_(false),
    pthreadId_(0),
    tid_(0),
    func_(std::move(func)),
    name_(n),
    latch_(1)
{
  setDefaultName();
}
void Thread::setDefaultName()
{
  int num = numCreated_.incrementAndGet();
  if (name_.empty())
  {
    char buf[32];
    snprintf(buf, sizeof buf, "Thread%d", num);
    name_ = buf;
  }
}

主要是start函数

void Thread::start()
{
  assert(!started_);
  started_ = true;
  // FIXME: move(func_)
  detail::ThreadData* data = new detail::ThreadData(func_, name_, &tid_, &latch_);
  if (pthread_create(&pthreadId_, NULL, &detail::startThread, data))
  {
    started_ = false;
    delete data; // or no delete?
    LOG_SYSFATAL << "Failed in pthread_create";
  }
  else
  {
    latch_.wait();
    assert(tid_ > 0);
  }
}

这里又有一个ThreadData类 作者将线程的运行函数放在全局函数中 这点有点不太明白 通过给类中设置静态函数 传递this指针也可以 以后再想想吧。

这是运行的函数 此处的CountDownLatch值得注意

 void runInThread()
  {
    *tid_ = muduo::CurrentThread::tid();
    tid_ = NULL;
    latch_->countDown();
    latch_ = NULL;

    muduo::CurrentThread::t_threadName = name_.empty() ? "muduoThread" : name_.c_str();
    ::prctl(PR_SET_NAME, muduo::CurrentThread::t_threadName);
    try
    {
      func_();
      muduo::CurrentThread::t_threadName = "finished";
    }
    catch (const Exception& ex)
    {
      muduo::CurrentThread::t_threadName = "crashed";
      fprintf(stderr, "exception caught in Thread %s\n", name_.c_str());
      fprintf(stderr, "reason: %s\n", ex.what());
      fprintf(stderr, "stack trace: %s\n", ex.stackTrace());
      abort();
    }
    catch (const std::exception& ex)
    {
      muduo::CurrentThread::t_threadName = "crashed";
      fprintf(stderr, "exception caught in Thread %s\n", name_.c_str());
      fprintf(stderr, "reason: %s\n", ex.what());
      abort();
    }
    catch (...)
    {
      muduo::CurrentThread::t_threadName = "crashed";
      fprintf(stderr, "unknown exception caught in Thread %s\n", name_.c_str());
      throw; // rethrow
    }
  }
};

void* startThread(void* obj)
{
  ThreadData* data = static_cast<ThreadData*>(obj);
  data->runInThread();
  delete data;
  return NULL;
}

下面是我参考作者的Thread写的一个程序 不过没有CountDownLatch 当时觉得没必要 接下来就凉凉 出bug了…

#ifndef __THREAD_H
#define __THREAD_H

#include <unistd.h>
#include <sys/syscall.h>


#include<iostream>
#include<functional>
#include<atomic>
namespace  mynamespace{

class Thread{
    
public:
    
    using Threadfunc =std::function<void()>;
    Thread(Threadfunc func,std::string &&name="");
    
    ~Thread();
    void started();
    std::string getName();

    pid_t getTid();
    void joined();
private:
    pid_t getid();
    void init();
    Threadfunc runThread;
    static void *callback(void *arg);
    pthread_t pthread_id_; //

    std::string name_;
    pid_t tid_; //
    bool started_;
    bool joined_;
    static std::atomic_int num_;
};
// std::atomic_int Thread::num_(0);
}
#endif 

#include"Thread.h"

namespace  mynamespace{

Thread::Thread(Threadfunc func,std::string&&name)
:name_(std::move(name))
,runThread(std::move(func))
,started_(false)
,joined_(false)
,pthread_id_(0)
,tid_(0){
    
    init();

}
std::atomic_int Thread::num_(0);
void Thread::started(){

    started_=true;
    
    if(pthread_create(&pthread_id_,
                NULL,callback,this)){
        started_=false;
        perror("pthread_create error");
    }else{
    
    
    }

}
void Thread::joined(){

  if(started_&&!joined_){
    joined_=true;
    pthread_join(pthread_id_,NULL);
  }  

}
pid_t Thread::getid(){
    
   return static_cast<pid_t>(syscall(SYS_gettid)); 
}
pid_t Thread::getTid(){

    return tid_;
}
std::string Thread::getName(){

    return name_;
}
Thread::~Thread(){
    
    if(started_&&!joined_){
        pthread_detach(pthread_id_);
    }
}
void Thread::init(){

    
    int id=num_.fetch_add(1);
    if(name_.empty()){
        char buf[30];
        snprintf(buf,sizeof(buf),"Thread%d\n",id);
        name_=buf; 
    }
}    

void *Thread::callback(void *arg){
    
    Thread *thr=(Thread*)arg;
	thr->tid_=thr->getTid(); 
    thr->runThread();
    
    
}
}

测试代码

#include<iostream>
#include<functional>
#include"Thread.h"


using namespace std;

using namespace mynamespace;
void threadfunc1(){
    
 
}
void threadfunc2(int i){

   
}
int main(){


    Thread t1(bind(threadfunc1),"My first thread");

    cout<<"t1 name"<<t1.getName()<<endl;
    
    t1.started();
    cout<<"t1.Tid"<<t1.getTid()<<endl;
    

    int i=10;
    Thread t2(bind(threadfunc2,ref(i)),"Second thread");
    
    t2.started();
    cout<<"t2.Tid"<<t2.getTid()<<endl;
 
}

结果在这里插入图片描述
在我加上printf大法后 出现了这种情况
在这里插入图片描述

可知线程还未启动主线程先输出了tid的值
可使线程创建后阻塞在此处 获取tid后再唤醒
在runInThread种 CurrentThread是作者用gcc提供的__thread线程局部数据 进行优化
这是CurentThread原型

namespace CurrentThread
{
  // internal
  extern __thread int t_cachedTid;
  extern __thread char t_tidString[32];
  extern __thread int t_tidStringLength;
  extern __thread const char* t_threadName;
  void cacheTid();

  inline int tid()
  {
    if (__builtin_expect(t_cachedTid == 0, 0))
    {
      cacheTid();
    }
    return t_cachedTid;
  }

  inline const char* tidString() // for logging
  {
    return t_tidString;
  }

  inline int tidStringLength() // for logging
  {
    return t_tidStringLength;
  }

  inline const char* name()
  {
    return t_threadName;
  }

  bool isMainThread();

  void sleepUsec(int64_t usec);  // for testing

  string stackTrace(bool demangle);
}  // namespace CurrentThread
}  // namespace muduo

#endif  // MUDUO_BASE_CURRENTTHREAD_H

其中__builtin_expect(!!(x),y) 表示期望x等于后面的y
!!表示所有非0值都变为1

#define likely(x)      __builtin_expect(!!(x), 1)
    #define unlikely(x)    ``__builtin_expect(!!(x), 0)

其中tid函数如下

inline int tid()
  {
    if (__builtin_expect(t_cachedTid == 0, 0))
    {
      cacheTid();
    }
    return t_cachedTid;
  }

表明我们希望t_cahedTid不为0 此时就不再需要调用chcheTid 此函数调用了syscall系统调用 不用每次切换到内核去获取tid
这玩意真绕 …

注意点:
__thread线程本地存储

线程本地存储(TLS)是一种机制,通过该机制分配变量,以便每个现有线程都有一个变量实例。 GCC用于实现此目标的运行时模型起源于IA-64特定于处理器的ABI,但此后也已迁移到其他处理器。它需要链接器(ld),动态链接器(ld.so)和系统库(libc.so和libpthread.so)的大力支持,因此并非到处都有它。

在用户级别,可以使用新的存储类关键字__thread看到扩展。例如:

__thread int i;
extern __thread结构状态s;
静态__thread char * p;
__thread说明符可以与extern或static说明符一起单独使用,但不能与其他存储类说明符一起使用。与extern或static一起使用时,__thread必须立即出现在其他存储类说明符之后。

__thread说明符可以应用于类的任何全局,文件作用域的静态,函数作用域的静态或静态数据成员。它可能不适用于块作用域自动或非静态数据成员。

将address-of运算符应用于线程局部变量时,将在运行时对其求值,并返回该变量的当前线程实例的地址。这样获得的地址可以被任何线程使用。当线程终止时,指向该线程中线程局部变量的任何指针都将变为无效。

静态初始化不能引用线程局部变量的地址。

在C ++中,如果存在用于线程局部变量的初始化程序,则该初始化程序必须为常量表达式,如ANSI / ISO C ++标准的5.19.2所定义。

其中

void afterFork()
{
  muduo::CurrentThread::t_cachedTid = 0;
  muduo::CurrentThread::t_threadName = "main";
  CurrentThread::tid();
  // no need to call pthread_atfork(NULL, NULL, &afterFork);
}

class ThreadNameInitializer
{
 public:
  ThreadNameInitializer()
  {
    muduo::CurrentThread::t_threadName = "main";
    CurrentThread::tid();
    pthread_atfork(NULL, NULL, &afterFork);
  }
};

针对多线程使用了fork
pthread_atfork()函数做清理锁的工作
再来看一个Threadlocal类

template<typename T>
class ThreadLocal : noncopyable
{
 public:
  ThreadLocal()
  {
    MCHECK(pthread_key_create(&pkey_, &ThreadLocal::destructor));
  }

  ~ThreadLocal()
  {
    MCHECK(pthread_key_delete(pkey_));
  }

  T& value()
  {
    T* perThreadValue = static_cast<T*>(pthread_getspecific(pkey_));
    if (!perThreadValue)
    {
      T* newObj = new T();
      MCHECK(pthread_setspecific(pkey_, newObj));
      perThreadValue = newObj;
    }
    return *perThreadValue;
  }

 private:

  static void destructor(void *x)
  {
    T* obj = static_cast<T*>(x);
    typedef char T_must_be_complete_type[sizeof(T) == 0 ? -1 : 1];
    T_must_be_complete_type dummy; (void) dummy;
    delete obj;
  }

 private:
  pthread_key_t pkey_;
};

pthread_key_create(pthread_key_t *keyp,
void (destor)(void));
创建与线程关联的键 destor正如c++的析构函数做清理工作 线程退出则会被调用
pthread_key_delete(pthread_key_t key)
取消键和线程特定数据的关联关系但并不会调用析构函数

int pthread_setspecific(pthread_key_t key,const void *value)
关联键和线程特定数据
void *pthread_getspecific(pthread_key_t key)
没有线程特定数据与键关联 则返回空指针

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值