zoukankan      html  css  js  c++  java
  • 从零开始构建一个Reactor模式的网络库(二)线程类Thread

    线程类Thread是对POSIX线程的封装类,因为要构建的是一个Linux环境下的多线程网络库,对线程的封装是很必要的。

    首先是CurrentThread命名空间,主要是获取以及缓存线程id:

     1 #ifndef CURRENTTHREAD_H
     2 #define CURRENTTHREAD_H
     3 #include <unistd.h>
     4 #include <sys/syscall.h>
     5 
     6 namespace CurrentThread
     7 {
     8     extern __thread int t_cachedTid;
     9     inline void cacheTid()
    10     {
    11         t_cachedTid=static_cast<int>(::syscall(SYS_gettid));
    12     }
    13     inline int tid()
    14     {
    15         if(t_cachedTid==0)
    16             cacheTid();
    17         return t_cachedTid;
    18     }
    19 }
    20 
    21 #endif // CURRENTTHREAD_H

    这里要注意一个问题,就是线程id的获取

    线程id的获取可以通过几种方式,最方便的是syscall(),是一个glibc库函数而不是一个系统调用,此时返回的是内核中的线程id。

    因为Linux的线程实现中,线程事实上也是一个进程,因此返回的tid事实上就是pid,pid_t在Linux中一般实现为int。

    另外,POSIX线程库提供了函数pthread_self(),但是该函数返回的是进程中的线程id,类型为pthread_t,一般是unsigned long类型,并不是内核中的实际id,在调试和排查错误时并不方便。

     1 #ifndef THREAD_H
     2 #define THREAD_H
     3 #include <pthread.h>
     4 #include <memory>
     5 #include <functional>
     6 #include "Types.h"
     7 #include <atomic>
     8 #include "Mutex.h"
     9 
    10 namespace mini
    11 {
    12 class Thread
    13 {
    14 public:
    15     typedef std::function<void()> ThreadFunc;
    16     explicit Thread(const ThreadFunc& func,const string& ThreadName=string());
    17     ~Thread();
    18 
    19     int join();
    20     void start();
    21     pid_t tid() const { return *tid_; }
    22     bool started() const { return started_; }
    23     const string& name() const {return name_;}
    24 private:
    25 
    26     void setDefaultName();
    27 
    28     bool started_;                        //if the thread started
    29     bool joined_;                         //if joined settled
    30     pthread_t pthreadId_;                 //thread id in the process
    31     std::shared_ptr<pid_t> tid_;          //shared_ptr to the tid
    32     string name_;                         //name of the thread
    33     ThreadFunc func_;                     //function for the thread
    34     static std::atomic<int> numsCreated_; //record nums of created threads
    35 };
    36 
    37 }
    38 
    39 #endif // THREAD_H

    Thread.h头文件中定义了Thread类,成员包括启动状态、tid和pthreadid、实际执行的函数以及名字等。

     1 #include "CurrentThread.h"
     2 #include "Thread.h"
     3 #include <stdio.h>
     4 #include <unistd.h>
     5 #include <sys/syscall.h>
     6 #include <sys/types.h>
     7 
     8 namespace CurrentThread
     9 {
    10 __thread int t_cachedTid=0;
    11 /*
    12 bool isMainThread()
    13 {
    14     return ::getpid()==tid();
    15 }
    16 */
    17 }
    18 namespace mini
    19 {
    20 struct ThreadData
    21 {
    22     typedef mini::Thread::ThreadFunc ThreadFunc;
    23     ThreadFunc func_;
    24     mini::string name_;
    25     std::weak_ptr<pid_t> wkTid_;
    26     ThreadData(const ThreadFunc& func,const string& name,const std::shared_ptr<pid_t>& tid)
    27         :func_(func),name_(name),wkTid_(tid)
    28     {}
    29     void runInThread()
    30     {
    31         pid_t tid=CurrentThread::tid();
    32         std::shared_ptr<pid_t> ptid=wkTid_.lock();
    33         if(ptid)
    34         {
    35             *ptid=tid;
    36             ptid.reset();
    37         }
    38         func_();
    39     }
    40 
    41 };
    42 std::atomic<int> Thread::numsCreated_(0);
    43 
    44 void Thread::setDefaultName()
    45 {
    46     int num=numsCreated_++;
    47     if(name_.empty())
    48     {
    49         char buf[32];
    50         snprintf(buf,sizeof buf,"Thread%d", num);
    51         name_=buf;
    52     }
    53 }
    54 
    55 void* startThread(void* obj)
    56 {
    57     ThreadData* data=static_cast<ThreadData*>(obj);
    58     data->runInThread();
    59     delete data;
    60     return NULL;
    61 }
    62 
    63 Thread::Thread(const ThreadFunc &func, const string &ThreadName)
    64     :started_(false),
    65       joined_(false),
    66       pthreadId_(0),
    67       tid_(new pid_t(0)),
    68       func_(func),
    69       name_(ThreadName)
    70 {
    71     setDefaultName();
    72 }
    73 
    74 void Thread::start()
    75 {
    76     started_=true;
    77     ThreadData* data=new ThreadData(func_,name_,tid_);
    78     if(pthread_create(&pthreadId_,NULL,&startThread,data));
    79     {
    80         started_=false;
    81         //delete data;
    82         //LOG_SYSFATAL<<"FAILED in pthread_create";
    83     }
    84 }
    85 
    86 int Thread::join()
    87 {
    88     joined_=true;
    89     return pthread_join(pthreadId_,NULL);
    90 }
    91 
    92 Thread::~Thread()
    93 {
    94     if(started_&&!joined_)
    95         pthread_detach(pthreadId_);
    96 }
    97 }

    由于向pthread_create中传递要执行的线程函数以及参数比较复杂,定义了一个内部类ThreadData。

    ThreadData中有一个weak_ptr<pid_t>,当线程实际被创建并开始运行时,创建一个临时的shared_ptr,确保Thread以及ThreadData被正确创建。

    事实上,Thread类对象创建时,线程并没有实际开始运行,直到调用start()才开始执行。

    执行线程可以调用join()来等待Thread线程的结束。默认情况下,线程资源会保留直到调用pthread_join()。

    析构函数简单地调用pthread_detach()来设置线程分离,从而在线程函数执行结束后直接退出,线程资源也会在线程终止时立即被回收

  • 相关阅读:
    jmeter实现multipart/form-data类型请求
    jmeter(正则提取器、json提取器)做接口关联
    windows使用ubuntu启动linux服务
    Jmeter+Ant+Jenkins环境搭建
    ubuntu网卡驱动的安装
    Ubuntu 挂载U盘
    Linux下安装jdk8步骤详述(转载)
    springboot项目:项目部署
    springboot项目:Redis缓存使用
    springboot项目:Redis分布式锁的使用(模拟秒杀系统)
  • 原文地址:https://www.cnblogs.com/lustar/p/10136007.html
Copyright © 2011-2022 走看看