首页 技术 正文
技术 2022年11月16日
0 收藏 313 点赞 2,939 浏览 4015 个字

在网络编程的时候往往需要对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() = ;
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();
}
}private:
int count_;
};int main(void)
{
TestThread t();
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();
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();
}
}class Foo
{
public:
Foo(int count) : count_(count){ } void MemerFunc()
{
while( count_-- )
{
cout << "This is a test" << endl;
sleep();
}
}
private:
int count_;};int main(void)
{ //Thread *t = new Thread(ThreadFunc); //Thread *t = new Thread(boost::bind(ThreadFunc2,4)); Foo foo();
Thread *t = new Thread(boost::bind(&Foo::MemerFunc,&foo)); t->setAutoDelete(true);
t->start();
t->join(); //do other work....}

在上面的例子中我们可以绑定不同的对象到Thread的构造函数中,这样就可以实现随着绑定的不同调用不同的函数。

上面就是线程用面向对象和基于对象的不同封装方式,如果你要问,它们孰优孰劣,请挪步这篇精彩的分析

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,117
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,590
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,435
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,206
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,842
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,927