c++封装线程


线程

(1)Linux线程库有两个流行的线程库,分别是LinuxThreads和NPTL,由于LinuxThreads的某些缺点,已经被NPTL取代,它们都是基于1:1模式实现,即1个用户线程被映射为1个内核线程;故每一个用户线程在内核中有唯一的标识

线程标识

使用pthread_t有问题!!!

void* loop(void*)  
{  
  cout  << "Thread run" << endl;  
  return NULL;  
}  
  
int main()  
{  
  pthread_t t1, t2;  
  
  errno = pthread_create(&t1, NULL, loop, NULL);  
  assert(!errno);  
  pthread_join(t1, NULL);  
  
  pthread_create(&t2, NULL, loop, NULL);  
  assert(!errno);  
  pthread_join(t2, NULL);  
  
  cout  << hex << t1 << " " << t2 << endl;  
  
  return 0;  
}  

说明几点:

(1)验证该代码片段可得:上述t1和t2值相同;Pthreads只能保证同一进程中各线程pthread_t在同一时刻不同,不能保证同一线程具有不同的id;

(2)pthread_t在某些应用场合不能作为线程的标识,比如一个线程已经死亡,而此时创建一个新的线程,可能重用了旧的pthread_t,导致本来与旧线程交互的数据,开始又和新的线程错误执行;

(3)解决办法:由于NPTL基于1:1模式(1个用户线程被映射为1个内核线程)实现;故每一个用户线程在内核中也有唯一的标识,使用gettid()可以获得该标识,为了减少系统调用次数,可使用__thread进行缓存该id,这样只有第一次使用该id才会调用gettid()系统调用,但是可移植性会降低;下述代码中__thread缓存tid;syscall(SYS_gettid)为直接使用系统调用号执行系统调用,即直接获取某执行线程的唯一线程ID;

实现代码如下:

namespace CurrentThread  
{  
  
pid_t gettid()  
{  
  return syscall(SYS_gettid);  
}  
  
__thread pid_t t_tid;  
  
static pthread_t tid()  
{  
  if (t_tid == 0)  
    {  
      t_tid = gettid();  
    }  
  
  return t_tid;  
}  
  
}  

  1. thread声明如下:

  1. namespace CurrentThread  
    {  
      
    extern __thread pid_t t_tid;  
    extern pid_t tid();  
      
    }  
      
    //notice: we should make Thread object's life longer than thread, so we shold always use fun: join,  
    class Thread final  
    {  
    public:  
      Thread(const Thread&) = delete;  
      Thread& operator=(const Thread&) = delete;  
      
      typedef std::function<void()> ThreadFunc;  
      
      explicit Thread(const ThreadFunc& func);  
      
      void start();  
      
      bool running() const  
      {  
        return _running;  
      }  
      
      int join()  
      {  
        int err = pthread_join(_threadId, NULL);  
        return err;  
      }  
      
      pid_t tid() const  
      {  
        return _tid;  
      }  
      
    private:  
      void _runInThread();  
      static void* _threadFunc(void*);  
      
      pid_t _tid;  
      pthread_t _threadId;  
      ThreadFunc _func;  
      bool _running;  
    };  

说明几点:

(1)_tid为线程的唯一标识,也就是利用上述CurrentThread和__thread来实现获得的;

(2)线程与Thread对象的生命周期,要注意Thread对象析构和线程终止的顺序关系;当调用thread.join()函数时,可以保证Thread对象在线程终止之后析构;若没有调用thread.join()函数,将会出现thread先析构的情况,此时C++析构会自动deatch线程,因此保证资源不会泄漏,但是线程在使用继续使用Thread相关资源时,执行过程将会出现未定义情况;因此我们应该保证使用thread.join()函数,即Thread的生命周期要长于线程的生命周期;

thread实现如下:
  1. __thread pid_t  CurrentThread::t_tid = 0;  
      
    pid_t CurrentThread::tid()  
    {  
      if (t_tid == 0)  
        t_tid = syscall(SYS_gettid);  
      
      return t_tid;  
    }  
      
    Thread::Thread(const ThreadFunc& func):  
        _func(func),  
        _running(false)  
    {  
      
    }  
      
    void Thread::start()  
    {  
      assert(!_running);  
      _running = true;  
      
      int err = pthread_create(&_threadId, NULL, Thread::_threadFunc, this);  
      if (err != 0)  
        {  
          cout << "pthread_create system error";  
        }  
    }  
      
    void Thread::_runInThread()  
    {  
      assert(_running);  
      try  
        {  
          _tid = CurrentThread::tid();       //impotant, the time we obtain tid;  
      
          cout << "Thread tid[" << _tid << "] is threadFunc";  
      
          if (_func)  
            _func();  
        }  
      catch (...)  
        {  
          cout << "Exception happen in Thread";  
        }  
    }  
      
    void* Thread::_threadFunc(void* obj)      //remember obj's scope in self class  
    {  
      Thread* thread = static_cast<Thread*>(obj);  
      thread->_runInThread();  
      return NULL;  
    }  

说明几点:

(1)static void* _threadFunc(void*)为Thread的static成员函数,而不是成员函数,因为pthread_create(&_threadId, NULL, Thread::_threadFunc, this)接收的函数类型必须是一个类似全局的函数,使用非static成员函数,显然我们还要传递相对应的对象指针,pthread_create是无法接收的;
(2)在_runInThread()中, 使用 catch (...)捕捉线程执行过程中的一切异常;
测试代码:
  1. #include <Base/Thread.h>  
    #include <stdio.h>  
      
    using namespace std;  
    using namespace Base;  
      
    void func1() {  
      printf("%s %d\n", "func1: tid", CurrentThread::tid());  
    }  
      
    void func2() {  
       printf("%s %d\n", "func2: tid", CurrentThread::tid());  
    }  
      
    int main(void) {  
      Thread thread1(func1);  
      Thread thread2(func2);  
        
      thread1.start();  
      thread2.start();  
        
      thread1.join();  
      thread2.join();  
      return 0;  
    }  





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值