多线程在网络编程中作用重大,由于创建/销毁线程、线程间通信的开销小,目前很多网络服务器都是用多线程(线程池)的模式对外提供服务。linux上开发多线程程序多使用pthread库,本文主要讨论使用C++封装pthread库时可能出现的问题。

 

封装pthread库主要有两种思路,第一种是简单的封装接口,如下所示:

 

  1. class simple_thread_t {
  2. public:
  3.     int start(void (*task)(void *), void *argp)
  4.     {
  5.         // do something else
  6.         pthread_create(&_tid, NULL, task, argp);
  7.     }
  8.     int join()
  9.     {
  10.         // do something else
  11.         pthread_join(_tid, NULL);
  12.     }
  13.     int detach()
  14.     {
  15.         pthread_detach(_tid);
  16.     }
  17.     // some other interfaces
  18. private:
  19.     pthread_t _tid;
  20. };


simple_thread_t只是简单的封装了pthread库的接口,但需要创建线程时,跟使用pthread库一样,需要先实现好线程例程函数,然后传递给start,线程执行时需要依赖的数据可以通过参数传递。

 

第二种封装方式则是在内部做了参数传递的工作,充分利用C++继承的特性,如下代码。

  1. class common_thread_t {
  2. public:
  3.     int start()
  4.     {
  5.          // do something else
  6.         pthread_create(&_tid, NULL, _process, (void *)this);
  7.     }
  8.     int join()
  9.     {
  10.         // do something else
  11.         pthread_join(_tid, NULL);
  12.     }
  13.     int detach()
  14.     {
  15.         pthread_detach(_tid);
  16.     }
  17.     // some other interfaces
  18.     virtual void run() = 0;
  19. private:
  20.     pthread_t _tid;
  21.     static void *_process(void *argp)
  22.     {
  23.         common_thread_t *thread = (common_thread_t*)argp;
  24.         thread->run();
  25.     }
  26. };

 

用户要创建线程,只需继承common_thread_t,并实现run接口即可,用户可以在子类中定义额外的数据以供run接口使用,在实现子类后,创建子类实例并调用start即可创建线程。

 

在使用common_thread_t时,有个限制,在线程没有正式运行之前,common_thread_t的对象不能销毁,否则会出现pure virtual function called的错误 因为在线程执行例程中需要调用run方法,而如果此时对象已销毁,则会找不到对应的虚函数。这个限制使得在需要创建需要detach线程时,new出来的common_thread_t对象,没有合适的时机来delete,因为不知道detach后的线程何时结束


2011年11月22日补充:
为了解决堆上创建线程释放的问题,可以使用boost::shared_ptr,让thread的run函数thread对象的的shared_ptr,使得在线程函数执行的过程中thread对象一直不会释放,等其线程函数执行完后才会被释放。

实现参考:https://gist.github.com/1384659 (作者:陈硕)


01-19 12:25