linux下线程的两种封装方式
来源:互联网 发布:资源管理系统源码 编辑:程序博客网 时间:2024/05/19 01:08
在网络编程的时候往往需要对Linux下原生的pthread库中的函数进行封装,使其使用起来更加方便,封装方法一般有两种:面向对象和基于对象,下面将分别介绍这两种方式,最后统一分析这两种方式的优缺点:
面向对象:
面向对象的封装方式是通过虚函数提供回调功能,我们创建一个Thread类,然后设置一个run虚函数,使用时只需要重载这个类并实现其中的虚函数即可:
具体实现如下:
//------thread.h----------------#ifndef _THREAD_H_#define _THREAD_H_#include <pthread.h>class Thread{public: Thread(); virtual ~Thread(); void start(); void join(); void setAutoDelete(bool autoDelete);private: static void* threadRoutine(void* args); virtual void run() = 0; pthread_t threadId_; bool autoDelete_;};#endif
//---------thread.c-------------------#include "thread.h"#include <iostream>using namespace std;Thread::Thread() : autoDelete_(false){ cout << "Thread..." << endl;}Thread::~Thread(){ cout << "~Thread..." << endl;}void* Thread::threadRoutine(void* arg){ Thread* thread = static_cast<Thread*>(arg); thread->run(); if (thread->autoDelete_) { delete thread; } return NULL;}void Thread::start(){ pthread_create(&threadId_,NULL, threadRoutine,this);}void Thread::join(){ pthread_join(threadId_, NULL);}void Thread::setAutoDelete(bool autoDelete){ autoDelete_ = autoDelete;}
调用方式如下:
#include "thread.h"#include <unistd.h>#include <iostream>using namespace std;class TestThread : public Thread{public: TestThread(int count) : count_(count) { cout << "TestThread..." << endl; } ~TestThread() { cout << "~TestThread..." << endl; }private: void run() { while( count_-- ) { cout << "This is a test" << endl; sleep(1); } }private: int count_;};int main(void){ TestThread t(5); t.start(); t.join(); //do other work....}
可以看到,其中有一个私有的重虚函数run,使用时只需要继承thread,实现run函数,并在其内实现线程需要执行的逻辑就可以了。
同时有一个静态的threadRoutine成员函数,因为C++成员函数缺省的调用方式是__thiscall,成员函数中隐含的第一个参数都是this指针,所以不能匹配给pthread_create的形参void *(*start_routine) (void *), 这时候就可以传递类的一个静态成员,把this指针做为该静态成员的参数。也就是start方法的: pthread_create(&threadId_,NULL, threadRoutine,this); 在threadRoutine函数中将接收到的void*类型的参数转换成Thread*就可以了,然后调用他的run方法。
在main函数中静态创建了一个TestThread变量 t,然后启动线程, 但是如果线程运行结束了,这个变量 t 就失去存在的价值了, 总不能一直让它在哪里占用着栈上空间吧,此时我们就可以动态创建TestThread, 然后设定其autoDelete_属性,这样当该线程执行完毕后就会检查是否需要delete掉这个堆上变量,这就是autoDelete_属性的作用,可以将main函数修改如下:
int main(void){ TestThread *t = new TestThread(5); t->setAutoDelete(true); t->start(); t->join(); //do other work....}
如果你决心只在堆上分配的话,就可以将析构函数设置为私有的,这样就可以只在堆上分配,但是你还得提供一个公有的自定义的析构方法。
基于对象
基于对象的封装方法,实现思路同上,但是它不是通过虚函数的方式实现回调的功能,而是通过函数绑定的方式, boost库中的bind/function可以实现将一个函数转换成另一种函数,就算是成员函数也可以,它相当于C++中的bind1st,bin2nd等函数适配器,在C++11中也实现了bind/function, 关于boost bind/function的使用方法,可以看这里。这里不做过多介绍。
用基于对象的封装方法如下:
//-------thread.h-------#ifndef _THREAD_H_#define _THREAD_H_#include <pthread.h>#include <boost/function.hpp>class Thread{public: typedef boost::function<void ()> ThreadFunc; explicit Thread(const ThreadFunc& func); ~Thread(); void start(); void join(); void setAutoDelete(bool autoDelete);private: static void* threadRoutine(void* args); void run(); bool autoDelete_; ThreadFunc func_; pthread_t threadId_;};#endif
其中在构造函数中需要ThreadFunc对象,这个函数就是在run中调用的实例,可以看下面代码:
//---------thread.cpp-----------#include "thread.h"#include <iostream>using namespace std;Thread::Thread(const ThreadFunc& func):autoDelete_(false),func_(func){ cout << "Thread..." << endl;}Thread::~Thread(){ cout << "~Thread..." << endl;}void Thread::run(){ func_();}void* Thread::threadRoutine(void* arg){ Thread* thread = static_cast<Thread*>(arg); thread->run(); if (thread->autoDelete_) { delete thread; } return NULL;}void Thread::start(){ pthread_create(&threadId_,NULL, threadRoutine,this);}void Thread::join(){ pthread_join(threadId_, NULL);}void Thread::setAutoDelete(bool autoDelete){ autoDelete_ = autoDelete;}
在主函数中调用方法也很简单:
#include "thread.h"#include <unistd.h>#include <iostream>#include <boost/bind.hpp>using namespace std;void ThreadFunc(){ cout << "ThreadFunc..." << endl;}void ThreadFunc2(int count){ while( count_-- ) { cout << "This is a test" << endl; sleep(1); }}class Foo{public: Foo(int count) : count_(count){ } void MemerFunc() { while( count_-- ) { cout << "This is a test" << endl; sleep(1); } }private: int count_;};int main(void){ //Thread *t = new Thread(ThreadFunc); //Thread *t = new Thread(boost::bind(ThreadFunc2,4)); Foo foo(3); Thread *t = new Thread(boost::bind(&Foo::MemerFunc,&foo)); t->setAutoDelete(true); t->start(); t->join(); //do other work....}
在上面的例子中我们可以绑定不同的对象到Thread的构造函数中,这样就可以实现随着绑定的不同调用不同的函数。
上面就是线程用面向对象和基于对象的不同封装方式,如果你要问,它们孰优孰劣,请挪步这篇精彩的分析。
- linux下线程的两种封装方式
- linux下线程的两种封装方式
- linux下线程的两种封装方式
- linux 下 线程封装
- 线程-实现线程的两种方式
- 两种封装模块方式的比较
- 封装jquery插件的两种方式
- Linux下的线程类封装
- Linux下设置环境变量的两种常用方式
- Linux下编译安装驱动的两种方式
- Linux下安装ADT 的两种方式
- linux下打包压缩的两种方式
- Linux下 磁盘扩容的两种方式
- Python线程编程的两种方式
- 创建线程两种方式的比较
- java 创建线程 的两种方式
- 创建线程两种方式的比较
- Python线程编程的两种方式
- nodejs实现表单数据的提交
- 20170226C++项目班08_修复bug/函数添加
- 寻找错误结点练习
- C++实现斐波那契数列 时间复杂度 空间复杂度
- 国码切换流程总结
- linux下线程的两种封装方式
- Android studio使用真机不打印Logcat
- shell 数组详解
- 欢迎使用CSDN-markdown编辑器
- Win7安装Cent OS 虚拟机
- Eclipse如何查看接口实现类快捷键
- git使用教程
- [NSString boolValue]
- 安居客Android项目架构演进