[C++多线程]在C++中实现类似Java::Thread的类
学过Java的人都知道Java语言原生支持线程操作,可以通过继承自Thread类创建线程,也可以通过实现Runnable接口实现,但在C++语言中并没有类似的支持,因此要么直接用系统API,但是对于不同的操作系统环境,系统API是不同的,需要在每一处调用的地方考虑兼容性问题,另外一种方式就是将API封装在一个类似于Java::Thread类中,同样将不同平台的兼容性问题也封装在这个类中。
首先确定目标,创建一个Thread类,其中包含run方法,在实际使用过程中,创建一个新类继承自Thread类,并且实现其run方法,通过thread类的指针调用start方法启动线程。
接着考虑实现问题,虽然已经定下类的基本接口,但最终仍然是要调用系统创建线程的系统API,以Linux为例,则是pthread_create函数,其原型如下:
/* Create a new thread, starting with execution of START-ROUTINE getting passed ARG. Creation attributed come from ATTR. The new handle is stored in *NEWTHREAD. */ extern int pthread_create (pthread_t *__restrict __newthread, const pthread_attr_t *__restrict __attr, void *(*__start_routine) (void *), void *__restrict __arg) __THROWNL __nonnull ((1, 3));
其中有四个参数,但第一个和第三个不能为NULL。其中第一个参数 __newthread为pthread_t类型的指针,而pthread_t在Linux的pthreadtypes.h中的定义为”typedef unsigned long int pthread_t;“无符号长整型数,返回的是新建子线程的pid;第二个参数为线程相关的属性,例如,在不需要子线程给父线程返回信息,父线程也不需要等待子线程结束之后再结束的情况下,我们可以将其设置为detach线程;第三个参数__start_routine为函数指针,指向子线程将要执行的函数,其指向的函数原型为 void* function( void* parameter) ;第四个参数__arg为将要传递给__start_routine函数的参数,即parameter对应的实参。
其中重点关注第三个参数__start_routine的原型,也就是线程能够调用的函数指针,对于C++中的全局函数作为实参当然没有任何问题,但是在C++类中,普通的成员函数是不能直接被调用的,需要通过对象的地址,因此不能作为__start_routine的实参。除了普通的类成员函数之外,还有一种参数的能够达到普通全局函数相同的效果,就是静态成员函数,其可以直接通过类名进行调用,而无需包含内存空间的类对象才可调用。也就是说,在Thread类中需要一个静态成员函数作为pthread_create的第三个参数的实参,假设定义为static void* Thread::proc(void* parameter)。但在C++面向对象的规则中,静态函数中是无法调用普通成员函数的,而且静态函数是无法定义为虚函数的,因此如何实现将普通成员函数在静态函数中调用就成为一个难题。
但回头再次查看pthread_create函数发现,其第四个参数为传递给__start_routine的参数,也就是说传递给静态成员函数Thread::proc的参数,而我们学过C++面向对象的人都知道每个C++类都包含一个隐含的this指针,那么是否可以将this作为pthread_create的第四个参数,也就是Thread::proc的实参呢,通过实际代码验证发现完全没有问题。至此,考虑过程完毕,直接上代码。
Thread.h文件内容如下:
/* * File: Thread.h * Author: sunsmile * * Created on October 22, 2015, 6:19 PM */ #ifndef THREAD_H #define THREAD_H #include <pthread.h> class Thread { public: Thread(); virtual ~Thread(); virtual void run()=0; void start(); void stop(); static void wait(Thread* p); static void* proc(void* para); private: Thread(const Thread& orig); private: pthread_t thread_id; }; #endif /* THREAD_H */
Thread.cpp源文件内容如下:
/* * File: Thread.cpp * Author: sunsmile * * Created on October 22, 2015, 6:19 PM */ #include "Thread.h" Thread::Thread() { } Thread::Thread(const Thread& orig) { } Thread::~Thread() { } void Thread::wait(Thread* p) { if (!p) { return; } pthread_join(p->thread_id, NULL); } void Thread::start() { int ret = pthread_create(&thread_id, NULL, Thread::proc, this); if (ret != 0) { return; } } void* Thread::proc(void* para) { Thread* pt = (Thread*) para; if (pt) { pt->run(); } }
ThreadA.h文件内容如下:
/* * File: ThreadA.h * Author: sunsmile * * Created on October 22, 2015, 7:07 PM */ #ifndef THREADA_H #define THREADA_H #include "Thread.h" #include <iostream> using namespace std; class ThreadA : public Thread{ public: ThreadA(); ThreadA(const ThreadA& orig); virtual ~ThreadA(); void run(); private: }; #endif /* THREADA_H */
ThreadA.cpp文件内容如下:
/* * File: ThreadA.cpp * Author: sunsmile * * Created on October 22, 2015, 7:07 PM */ #include "ThreadA.h" ThreadA::ThreadA() { } ThreadA::ThreadA(const ThreadA& orig) { } ThreadA::~ThreadA() { } void ThreadA::run() { for (int i = 0; i < 10; i++) { cout << "This is Thread A" << endl; } }
main.cpp文件内容如下,其中ThreadB的定义和ThreadA除ThreadA::run中输出语句中的A替换为B之外,没有任何区别:
/* * File: main.cpp * Author: sunsmile * * Created on October 22, 2015, 6:15 PM */ #include <iostream> using namespace std; #include "ThreadA.h" #include "ThreadB.h" int main(int argc, char** argv) { Thread* p1, *p2; p1=new ThreadA(); p2=new ThreadB(); p1->start(); p2->start(); Thread::wait(p1); Thread::wait(p2); cout<<"Main thread"<<endl; return 0; }
该程序的输出内容如下,当然由于三个线程的执行顺序由操作系统根据当前上下文调度得到的,所以每次的执行结果都可能会与上次不一样:
This is ThreadBThis is Thread A This is ThreadB This is ThreadB This is ThreadB This is ThreadB This is ThreadB This is ThreadB This is ThreadB This is ThreadB This is ThreadB This is Thread A This is Thread A This is Thread A This is Thread A This is Thread A This is Thread A This is Thread A This is Thread A This is Thread A Main thread RUN FINISHED; exit value 0; real time: 1s; user: 0ms; system: 0ms
评论:
2015-10-23 15:43