博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【C/C++开发】C++ Thread对象封装
阅读量:5147 次
发布时间:2019-06-13

本文共 3097 字,大约阅读时间需要 10 分钟。

Pthread库是posix linux的线程库,调用接口如下,我们模仿JDK,对Thread进行封装,具体的业务逻辑只需要如同Thread一样实现run方法即可。

线程操纵函数(简介起见,省略参数)

():创建一个线程
():终止当前线程
pthread_cancel():中断另外一个线程的运行
():阻塞当前的线程,直到另外一个线程运行结束
():初始化线程的属性
pthread_attr_setdetachstate():设置脱离状态的属性(决定这个线程在终止时是否可以被结合)
pthread_attr_getdetachstate():获取脱离状态的属性
():删除线程的属性
():向 发送一个信号
 
 首先,构造一个run接口如下:
class 
TC_Runable
{
public
:
    
virtual 
~TC_Runable(){};
    
virtual 
void 
run() = 0;
};
声明线程基础类:
/**
 * 线程基类.
 * 线程基类,所有自定义线程继承于该类,同时实现run接口即可,
  
 * 可以通过TC_ThreadContorl管理线程。
 */
class 
TC_Thread 
: 
public 
TC_Runable
{
public
:
     
/**
     * @brief  构造函数
      */
     TC_Thread();
     
/**
     * @brief  析构函数
      */
     
virtual 
~TC_Thread(){};
     
/**
     * @brief  线程运行
      */
     
TC_ThreadControl 
start();
    
/**
     * @brief  获取线程控制类.
     *
     * @return ThreadControl
     */
    
TC_ThreadControl 
getThreadControl() 
const
;
    
/**
     * @brief  线程是否存活.
     *
     * @return bool 存活返回true,否则返回false
     */
    
bool 
isAlive() 
const
;
     
/**
     * @brief  获取线程id.
      *
      * @return pthread_t 线程id
      */
     pthread_t id() {
 
return 
_tid
; }
protected
:
     
/**
      * @brief  静态函数, 线程入口.
      * 
      * @param pThread 线程对象
      */
     
static 
void 
threadEntry(
TC_Thread 
*pThread);
     
/**
     * @brief  运行
      */
    
virtual 
void 
run() = 0;
protected
:
    
/**
     * 是否在运行
     */
    
bool
            
_running
;
    
/**
     * 线程ID
     */
    pthread_t      
_tid
;
    
/**
     * 线程锁
     */
    
TC_ThreadLock
   
_lock
;
};
根据Pthread提供的接口实现该Thread类。
线程构造函数:
TC_Thread::TC_Thread() : 
_running
( 
false
), 
_tid
(-1)
{
}
初始化tid为-1,线程状态running为false。
线程执行入口,该方法声明的时候必须为静态方法,因为该方法符合pthread_create方法中的函数指针的类型,该方法将会回调thread的具体的子类
重载
的run方法,thread子类的实例通过指针传递进来。
void 
TC_Thread::threadEntry( 
TC_Thread 
*pThread)
{
    pThread->
_running 
= 
true
;
    {
        
TC_ThreadLock
::
Lock 
sync(pThread-> 
_lock
);
        pThread-> 
_lock
.notifyAll();
    }
    
try
    {
        pThread->run();
    }
    
catch
(...)
    {
        pThread-> 
_running 
= 
false
;
        
throw
;
    }
    pThread->
_running 
= 
false
;
}
通过调用start方法线程开始执行,但并不负责具体的执行逻辑,所以该方法对于start来说是通过的,是调用pthread_ctreat的地方,在该方法中,会调用this.threadEntity函数,通过其回调this.run()
TC_ThreadControl 
TC_Thread::start()
{
    
TC_ThreadLock
::
Lock 
sync(
_lock
);
    
if
(
_running
)
    {
        
throw 
TC_ThreadThreadControl_Exception
(
"[TC_Thread::start] thread has start"
);
    }
    
int 
ret = pthread_create(&
_tid 
,
                   0,
                   ( 
void 
*(*)( 
void 
*))& threadEntry,
                   ( 
void 
*) 
this
);
    
if
(ret != 0)
    {
        
throw 
TC_ThreadThreadControl_Exception
(
"[TC_Thread::start] thread start error"
, ret);
    }
    
_lock
.wait();
    
return 
TC_ThreadControl
(
_tid
);
}
获取线程控制工具类
TC_ThreadControl 
TC_Thread::getThreadControl () 
const
{
    
return 
TC_ThreadControl
(
_tid
);
}
判断线程当前状态。
bool 
TC_Thread::isAlive() 
const
{
    
return 
_running
;
}
整个线程类封装设计的难点在于,如果保证running的同步,我们必须保证线程真正在执行run方法的时候,该running设置为true,也就是说不能单纯的在start中变更该状态,因为此时有可能threadEntity并没有被执行(Pthread_creat)
在start方法中,首先便获取锁并顺序执行,但是start方法并不返回将wait住(3)(因为此事线程提方法并不一定成功执行,也就是说start能够返回的标志是该线程状态必须为running,否则在业务层面执行完start方法紧接着判断线程isalive却返回false会给调用者带来迷茫,甚至导致重复启动),threadEntity执行时表明pthread_create方法已经开始执行了,新线程执行OK,此时该方法将running设置为true(1),并且试图获取锁,此时如果wait已经执行,则获取锁操作可以成功,如果wait不成功,则会阻塞在这里等待wait操作的到来释放锁。
    {
        
TC_ThreadLock
::
Lock 
sync(pThread-> 
_lock
);
        pThread-> 
_lock
.notifyAll();
    }
这个大括号很重要,表示sync的生命周期在大括号结束的时候会释放,锁释放代表着notifyAll生效(真正的通知wait解除阻塞是在锁释放的时候进行的,因为wait需要重新获取锁),此时running为true,start方法可以安全返回了。当方法进行完之后,将running重新设置为false(2)。

转载于:https://www.cnblogs.com/huty/p/8517386.html

你可能感兴趣的文章
session丢失问题
查看>>
Python 批量修改root密码
查看>>
ThinkSNS+ 基于 Laravel master 分支,从 1 到 0,再到 0.1
查看>>
WEB服务器:Apache、Tomcat、JBoss、WebLogic、Websphere、IIS的区别与关系
查看>>
软件工程 speedsnail 冲刺7
查看>>
虚拟机CentOS设置IP
查看>>
Django之ORM多对多表创建方式,AJAX异步提交,分页器组件等
查看>>
SqlServer查询表名的备注(查询表名描述 MS_Description)
查看>>
Set集合HashSet,TreeSet
查看>>
Visual Studio 2015 终于还是装上了
查看>>
libusb(.NET)开源项目使用小结
查看>>
windows下 gvim 配置
查看>>
no route to host解决方案、Failed to start LSB: Bring up/down networking的问题解决方案
查看>>
去哪网实习总结:递归构建“流程运行顺序”的XML文件(JavaWeb)
查看>>
机器学习笔记十三:Ensemble思想(上)
查看>>
Unity3D中组件事件函数的运行顺序
查看>>
启动tomcat时出现乱码——淇℃伅(转)
查看>>
9.1 正睿提高2
查看>>
HDU.1693.Eat the Trees(插头DP)
查看>>
Java基本语法——(用于日后复习)
查看>>