C++学习之路: 线程封装(基于对象编程)
引言:
此次我们重新封装线程, 采用基于对象编程的方式,不用于面向对象编程中重定义虚函数的方式,这里我们用回调函数的方式。
Thread.h
1 #ifndef THREAD_H_ 2 #define THREAD_H_ 3 4 #include <boost/noncopyable.hpp> 5 #include <functional> 6 #include <pthread.h> 7 8 class Thread : boost::noncopyable 9 { 10 public: 11 typedef std::function<void ()> ThreadCallback; 12 13 Thread(ThreadCallback callback); 14 ~Thread(); 15 16 void start(); 17 void join(); 18 19 static void *runInThread(void *); 20 21 private: 22 pthread_t threadId_; 23 bool isRunning_; 24 ThreadCallback callback_; //回调函数 25 }; 26 27 28 29 #endif //THREAD_H_
可以看到没有重定义虚函数, 而是设置了一个函数适配器, 用于保存我们想要的业务逻辑。
直接用 静态函数 runInThread 调用 callback_即可。
Thread.cpp
1 #include "Thread.h" 2 3 Thread::Thread(ThreadCallback callback) 4 : threadId_(0), 5 isRunning_(false), 6 callback_(std::move(callback)) 7 { 8 9 } 10 11 Thread::~Thread() 12 { 13 if(isRunning_) 14 { 15 //detach 16 pthread_detach(threadId_); 17 } 18 } 19 20 void Thread::start() 21 { 22 pthread_create(&threadId_, NULL, runInThread, this); 23 isRunning_ = true; 24 } 25 void Thread::join() 26 { 27 pthread_join(threadId_, NULL); 28 isRunning_ = false; 29 } 30 31 void *Thread::runInThread(void *arg) 32 { 33 Thread *pt = static_cast<Thread*>(arg); 34 pt->callback_(); //调用回调函数 35 36 return NULL; 37 }
以上 有几点经验处理, Google推荐 当Thread 这个类析构时,如果线程还没有执行完, 那么就detach。
并设置一个标志位 bool isRunning 标志线程是否启动。
测试代码
1 #include "Thread.h" 2 #include <stdio.h> 3 #include <unistd.h> 4 using namespace std; 5 6 void foo() 7 { 8 while(1) 9 { 10 printf("foo\n"); 11 sleep(1); 12 } 13 } 14 15 16 17 int main(int argc, char const *argv[]) 18 { 19 Thread t(&foo); 20 21 t.start(); 22 t.join(); 23 24 return 0; 25 }
可以看到, 当用基于对象编程时, 不需要在定义用户自己的类了, 只需在主函数传入一个函数适配器即可。 具体函数类型可以用bind来实现。
测试代码2
1 #include "Thread.h" 2 #include <stdio.h> 3 #include <unistd.h> 4 using namespace std; 5 6 class Foo 7 { 8 public: 9 void foo(int i) 10 { 11 while(1) 12 { 13 printf("foo %d\n", i++); 14 sleep(1); 15 } 16 } 17 }; 18 19 20 21 int main(int argc, char const *argv[]) 22 { 23 Foo f; 24 int i = 34; 25 Thread t(bind(&Foo::foo, &f, i)); 26 27 t.start(); 28 t.join(); 29 30 return 0; 31 }
对于 类的成员函数 同理使用 大杀器bind