C++11提供了thread,但是过于复杂,我们还是倾向于在项目中编写自己的Thread。

Posix Thread的使用这里不再赘述。

重点是这个函数:

  1. #include <pthread.h>
  2. int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
  3. void *(*start_routine) (void *), void *arg);

第三个参数是一个回调函数,该函数必须返回值为void*,而且只有一个参数,类型也是void*。

POSIX的thread默认是joinable,需要手工调用pthread_join函数来回收,也可以调用pthread_detach将其变为detachable,此时不需要手工回收线程。

下面介绍Thread的封装。

我们把Thread的声明先放在这里:

  1. #ifndef THREAD_H_
  2. #define THREAD_H_
  3.  
  4. #include "NonCopyable.h"
  5. #include <pthread.h>
  6.  
  7. class Thread : NonCopyable
  8. {
  9. public:
  10. Thread();
  11. virtual ~Thread();
  12.  
  13. void start();
  14. void join();
  15.  
  16. virtual void run() = 0;
  17.  
  18. pthread_t getThreadId() const
  19. { return threadId_; }
  20.  
  21. private:
  1. //提供给pthread_create的第三个参数使用
  2. static void *runInThread(void *arg);
  3.  
  4. pthread_t threadId_;
  5. //pid_t tid_; //进程标示
  6. bool isRunning_;
  7. };
  8.  
  9. #endif //THREAD_H_

这里需要说明的是:

首先,为了获得最干净的语义,Thread应该是不可复制的,所以需要继承NonCopyable。

其次,为了调用pthread_create创建线程,我们往里面注册的不能是一个成员函数,因为成员函数含有一个隐式参数,导致函数的指针类型并不是void *(*start_routine) (void *),所以我们采用了static函数

static函数无法访问某一对象的成员,所以我们在调用pthread_create时,将this指针作为回调函数的参数

这里相关代码如下:

  1. //static
  2. void *Thread::runInThread(void *arg)
  3. {
  4. Thread *pt = static_cast<Thread*>(arg);
  5. //pt->tid_ = syscall(SYS_gettid);
  6. pt->run();
  7. return NULL;
  8. }

用户将自己的逻辑注册在run中就可以了。

这个Thread不提供detach函数,因为我们在析构函数中做了如下的处理,如果Thread对象析构,线程还在运行,那么需要将Thread设置为detach状态

  1. Thread::~Thread()
  2. {
  3. if(isRunning_)
  4. {
  5. pthread_detach(threadId_);
  6. }
  7. }

大部分逻辑都是固定的,用户只需要改变run里面的代码即可,于是我们将run设置为纯虚函数,让用户继承Thread类

所以析构函数为virtual

完整的CPP实现如下:

  1. #include "Thread.h"
  2. #include <assert.h>
  3. #include <unistd.h>
  4. #include "MutexLock.h" //TINY_CHECK
  5.  
  6. Thread::Thread()
  7. :threadId_(0),
  8. isRunning_(false)
  9. {
  10.  
  11. }
  12.  
  13. Thread::~Thread()
  14. {
  15. if(isRunning_)
  16. {
  17. TINY_CHECK(!pthread_detach(threadId_));
  18. }
  19. }
  20.  
  21. //static
  22. void *Thread::runInThread(void *arg)
  23. {
  24. Thread *pt = static_cast<Thread*>(arg);
  25. //pt->tid_ = syscall(SYS_gettid);
  26. pt->run();
  27. return NULL;
  28. }
  29.  
  30. void Thread::start()
  31. {
  32. TINY_CHECK(!pthread_create(&threadId_, NULL, Thread::runInThread, this));
  33. isRunning_ = true;
  34. }
  35.  
  36. void Thread::join()
  37. {
  38. assert(isRunning_);
  39. TINY_CHECK(!pthread_join(threadId_, NULL));
  40. isRunning_ = false;
  41. }

测试代码如下:采用继承的方式使用这个类。

  1. #include "Thread.h"
  2. #include <iostream>
  3. #include <unistd.h>
  4. using namespace std;
  5.  
  6. class MyThread : public Thread
  7. {
  8. public:
  9. void run()
  10. {
  11. cout << "foo" << endl;
  12. }
  13. };
  14.  
  15. int main(int argc, char const *argv[])
  16. {
  17. MyThread t;
  18. t.start();
  19.  
  20. t.join();
  21.  
  22. return 0;
  23. }

NonCopyable类的定义如下:

  1. #ifndef NONCOPYABLE_H
  2. #define NONCOPYABLE_H
  3.  
  4. class NonCopyable //禁用值语义
  5. {
  6. public:
  7. NonCopyable() { }
  8. ~NonCopyable() { }
  9. private:
  10. NonCopyable(const NonCopyable &);
  11. void operator=(const NonCopyable &);
  12. };
  13.  
  14. #endif //NONCOPYABLE_H

Linux组件封装(三)使用面向对象编程封装Thread的更多相关文章

  1. python面向对象编程 -- 封装、继承

    面向对象编程 -- 封装.继承 面向对象编程三要素:封装.继承和多态.本文主要看和封装.继承相关的概念:在python中多态的概念比较模糊,本文不做讨论. 1 封装 封装:将数据和操作组装到一起,对外 ...

  2. 进击的Python【第六章】:Python的高级应用(三)面向对象编程

    Python的高级应用(三)面向对象编程 本章学习要点: 面向对象编程介绍 面向对象与面向过程编程的区别 为什么要用面向对象编程思想 面向对象的相关概念 一.面向对象编程介绍 面向对象程序设计(英语: ...

  3. Python学习-第三天-面向对象编程基础

    Python学习-第三天-面向对象编程基础 类和对象 简单的说,类是对象的蓝图和模板,而对象是类的实例.这个解释虽然有点像用概念在解释概念,但是从这句话我们至少可以看出,类是抽象的概念,而对象是具体的 ...

  4. Objective-C 基础教程第三章,面向对象编程基础知

    目录 Objective-C 基础教程第三章,面向对象编程基础知 0x00 前言 0x01 间接(indirection) 0x02 面向对象编程中使用间接 面向过程编程 面向对象编程 0x03 OC ...

  5. Javascript 面向对象编程—封装

      前  言 Javascript是一种基于对象(object-based)的语言,你遇到的所有东西几乎都是对象.但是,它又不是一种真正的面向对象编程(OOP)语言,因为它的语法中没有class(类) ...

  6. Python学习札记(三十) 面向对象编程 Object Oriented Program 1

    参考:OOP NOTE 1.面向对象编程--Object Oriented Programming,简称OOP,是一种程序设计思想.OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数. ...

  7. objective-c自学总结(三)---面向对象的封装,继承与多态

    面向对象的三大特性 封装 继承 多态 1.封装: 隐藏属性,方法或实现细节的过程称为封装 信息隐藏,隐藏对象的实现细节,不允许用户看到 将东西包装在一 然后以新的完整形式呈现出来 例如,两种或多种化学 ...

  8. 面向对象编程(封装、封装的意义、封装与扩展性、@property)

    1.封装之如何实现属性的隐藏 封装: __x=1 # 把数据属性隐藏 (如何实现隐藏) 类定义阶段 __开头发生了变形 __x --> _A__x特点: 1.在类外部无法直接:obj.__Att ...

  9. Day11继承、封装、多态-面向对象编程(2)

    封装 我们设计程序要追求 高内聚,低耦合 . 高内聚:类的内部数据操作细节自己完成,不允许外部干涉 低耦合:仅暴露少量方法给外部使用 封装(数据的隐藏) 通常,应禁止直接访问一个对象中数据的实际表示, ...

随机推荐

  1. nginx 根据url访问次数限制

    #获取日期 date=`date +"%y%m%d"` #设置日志路径 data="/data/logs/abc.com/access.log" #配置文件路径 ...

  2. 从linux看android之二--java世界的盘古女娲

    在linux从内核态进入用户态运行init进程后启动的一个进程就是zygote.zygote是在android系统中创建java世界的盘古,他创建了第一个java虚拟机,同时他又是女娲,他成功地繁殖了 ...

  3. ffmpeg muxer 参数简要说明

    参数 值 说明 movflags MP4 Muxer 标记 rtphint 增加RTP的hint track empty_moov 初始化空的moov box frag_keyframe 在视频关键帧 ...

  4. hdu 3264(枚举+二分+圆的公共面积)

    Open-air shopping malls Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/ ...

  5. (16)C#继承

    继承格式 class 子类:父类 { ....... } 1.子类能够继承父类所有的字段和方法. class Program { class Father { ; public void b() { ...

  6. HDU 6113 度度熊的01世界【DFS/Flood Fill】

    度度熊的01世界 Accepts: 967 Submissions: 3064 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/3 ...

  7. haproxy代理kibana、nginx代理kibana并实现登录验证

    在使用ELK进行日志统计的时候,由于Kibana自身并没有身份验证的功能,任何人只要知道链接地址就可以正常登录到Kibana控制界面,由于日常的查询,添加和删除日志都是在同一个web中进行,这样就有极 ...

  8. Maximum Product of Word Lengths -- LeetCode

    Given a string array words, find the maximum value of length(word[i]) * length(word[j]) where the tw ...

  9. luogu P2776 [SDOI2007]小组队列

    题目背景 嘛,这道非常简单的给大家提供信心的省选题洛谷居然没有! 这么简单的题怎么可以没有! 给大家提升士气是义不容辞的责任! 所以我就来补一下啦.. 值得一提的是,标程是我自己做的.. 很渣,因为数 ...

  10. 每天一个linux命令7之telnet

    telnet :和端口通信         telnet   192.168.196.200 20 退出:      ctrl+]  然后在telnet 命令行输入 quit