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

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

重点是这个函数:

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

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

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

下面介绍Thread的封装。

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

#ifndef THREAD_H_
#define THREAD_H_ #include "NonCopyable.h"
#include <pthread.h> class Thread : NonCopyable
{
public:
Thread();
virtual ~Thread(); void start();
void join(); virtual void run() = 0; pthread_t getThreadId() const
{ return threadId_; } private:
    //提供给pthread_create的第三个参数使用
static void *runInThread(void *arg); pthread_t threadId_;
//pid_t tid_; //进程标示
bool isRunning_;
}; #endif //THREAD_H_

这里需要说明的是:

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

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

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

这里相关代码如下:

//static
void *Thread::runInThread(void *arg)
{
Thread *pt = static_cast<Thread*>(arg);
//pt->tid_ = syscall(SYS_gettid);
pt->run();
return NULL;
}

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

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

Thread::~Thread()
{
if(isRunning_)
{
pthread_detach(threadId_);
}
}

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

所以析构函数为virtual

完整的CPP实现如下:

#include "Thread.h"
#include <assert.h>
#include <unistd.h>
#include "MutexLock.h" //TINY_CHECK Thread::Thread()
:threadId_(0),
isRunning_(false)
{ } Thread::~Thread()
{
if(isRunning_)
{
TINY_CHECK(!pthread_detach(threadId_));
}
} //static
void *Thread::runInThread(void *arg)
{
Thread *pt = static_cast<Thread*>(arg);
//pt->tid_ = syscall(SYS_gettid);
pt->run();
return NULL;
} void Thread::start()
{
TINY_CHECK(!pthread_create(&threadId_, NULL, Thread::runInThread, this));
isRunning_ = true;
} void Thread::join()
{
assert(isRunning_);
TINY_CHECK(!pthread_join(threadId_, NULL));
isRunning_ = false;
}

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

#include "Thread.h"
#include <iostream>
#include <unistd.h>
using namespace std; class MyThread : public Thread
{
public:
void run()
{
cout << "foo" << endl;
}
}; int main(int argc, char const *argv[])
{
MyThread t;
t.start(); t.join(); return 0;
}

NonCopyable类的定义如下:

#ifndef NONCOPYABLE_H
#define NONCOPYABLE_H class NonCopyable //禁用值语义
{
public:
NonCopyable() { }
~NonCopyable() { }
private:
NonCopyable(const NonCopyable &);
void operator=(const NonCopyable &);
}; #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. [ CodeVS冲杯之路 ] P3145

     不充钱,你怎么AC? 题目:http://codevs.cn/problem/3145/ 经典的汉诺塔问题 我们移动的时候,如果是最小的1号就可以直接移动,否则先将上面的x-1号先移动到借用塔上,然 ...

  2. 杭电oj2072

    因为一直不能ac先发这里,希望有看到的大佬能指点一二. 先讲一下我的基本思路,首先将一整行数据保存在数组中,接着遍历数组,根据空格将每个单词存入二维数组中,最后遍历二维数组,找出其中不同的单词并计数. ...

  3. error C2440: 'static_cast' : cannot convert from 'UINT (__thiscall CStaticLink::* )(CPoint)' to 'LRESULT (__thiscall CWnd::* )(CPoint) (转)

    原文转自 http://blog.csdn.net/yinxing408033943/article/details/7601698 解决方法: 找到  UNIT CStaticLink::OnNcH ...

  4. Java错误随手记

    一.Eclipse启动时提示: An internal error occurred during: "Initializing Java Tooling" 1.关闭Eclipse ...

  5. Jquery实现逐屏加载图片

    引用jquery.scrollLoading.js $(document).ready(function () { //实现图片慢慢浮现出来的效果 $("img").load(fu ...

  6. 解决:laravel出现Please provide a valid cache path.

    SVN检出版本库上的项目后,访问首页出现如下提示: Please provide a valid cache path. 解决方法如下: 1.确保storage目录下有如app,framework,v ...

  7. C# Socket的粘包处理(转)

    http://www.cnblogs.com/aarond/p/Socket111.html 当socket接收到数据后,会根据buffer的大小一点一点的接收数据,比如: 对方发来了1M的数据量过来 ...

  8. [BZOJ2223][BZOJ3524][Poi2014]Couriers 主席树

    3524: [Poi2014]Couriers Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 2436  Solved: 960[Submit][St ...

  9. js-获取用户移动端网络类型:wifi、4g、3g、2g...

    今天工作时间很宽裕, 忽然想起,自己做过的所有页面中,有些页面经常会面临用户在网络状态很差的时候打开页面,页面是挂了的状态,感觉很LOW~. 所以我决定在今后的页面中我需要先判断用户的网络状态, 若是 ...

  10. ARC 098 D - Xor Sum 2

    Problem Statement There is an integer sequence A of length N. Find the number of the pairs of intege ...