本文适合对多线程Thread原理比较感兴趣的同学阅读,需要具备一定的C++和Java编程知识。
一、背景
最近学习Java多线程编程,发现Java标准库中的java.lang.Thread接口定义十分友好简洁,使用起来十分方便。不禁想起之前用C/C++写多线程时的烦恼,总会写一些pthread_*函数。于是萌生了这个念头,希望用C++实现一套类似Java Thread的库,简化以后的C++多线程开发。
二、C++ Thread用法
为了最大化地接近java.lang.Thread,同时方便Java开发者快速学习C++ Thread库,本库在使用上与Java完全一致,示例代码为:
#include <iostream>
#include <unistd.h>
#include <Thread.h>
class SimpleThread: public Thread
{
public:
virtual void run()
{
Thread::run();
std::cout << "I am a Thread\n";
sleep(2);
}
~SimpleThread()
{
std::cout << "I can free myself\n";
}
};
int main(int argc, char* argv[])
{
SimpleThread *thread = new SimpleThread;
thread->start();
return 0;
}
正如你所见,Thread类使用起来十分简洁。你只需要包含Thread.h文件,然后按照Java Thread的用法编写多线程程序就可以了。
代码地址在https://github.com/xhjcehust/Thread.git,文件目录结构为:
.
|-- src
| |-- Alias.h
| |-- Exception
| | |-- BaseException.h
| | |-- IllegalArgumentException.h
| | |-- IllegalThreadStateException.h
| | `-- ThreadCreateFailedException.h
| |-- Makefile
| |-- RefCountable.h
| |-- Runnable.cpp
| |-- Runnable.h
| |-- RunnablePtr.h
| |-- Thread.cpp
| |-- Thread.h
| |-- ThreadEntry.cpp
| |-- ThreadEntry.h
| |-- UnCopyable.h
| |-- _Runnable.h
| `-- _Thread.h
`-- test
|-- Makefile
|-- RunnableTest.cpp
|-- SimpleThreadTest.cpp
`-- SyncTest.cpp
使用之前,先进入src文件夹编译生成静态Thread库:
git clone https://github.com/xhjcehust/Thread.git
cd Thread/src
make
然后编译链接自己的main文件,以上述SimpleThreadTest.cpp文件为例,对应的编译命令为:
g++ -I ../src -o SimpleThreadTest SimpleThreadTest.cpp ../src/Thread.a -lpthread
生成SimpleTest可执行文件,运行效果为:
三、C++ Thread实现
在上面的示例中,我们发现两件有意思的事情:
-
动态申请的SimpleThread实例不需要释放,内存泄漏?No~
-
没有pthread_join,主线程为何会等到子线程sleep 2s退出才退出?
先看下Thread库的框架构成:
是的,你没看错,Thread.a调用了你所写的main函数!!!在最后编译生成的文件之中,Main函数事实上被重命名为__Main函数,真正地main函数隐藏在Thread.a之中。这种设计在开发者无感知的情况下将其编写的main函数作为Thread.a的一个模块来执行,其优点在于:
-
接管main函数所代表的主线程,在main函数执行之后实现资源的清理工作,如join等待子线程执行完成
-
捕获主线程执行过程中的异常,确保进程不会因为主线程的异常导致其他线程停止
但是,也给开发者带来了一点限制:main函数的声明的格式为:
int main(int argc, char* argv[])
但事实上,这种声明是普遍适用的声明方式,有利于规范平时的编程习惯。 另外,__Main这个符号已经被Thread库所使用,在编写的main文件中也不能使用这个符号,需要重定义。
细心的读者可能发现,示例之中的Thread对象通过new申请堆上内存,而不是栈上分配。主要原因在于C++栈上对象的生命周期在退栈时销毁,而线程内需要引用Thread对象,因此,Thread库限制只能在堆上构造对象,栈上构造会编译出错。
至于SimpleThread实例不需要主动释放这点,在子线程执行完之后,Thread库会自动释放线程申请的Thread对象资源。
四、C++ Thread开发进度
到目前为止,Thread库实现的功能包括:
-
基础Thread类和Runnable类功能
-
synchronize同步语句块功能
后续需要开发的功能包括:
-
线程停止,暂停,信号等
-
Thread线程间通信互斥机制
-
支持线程组等特性。
-
....
项目地址:https://github.com/xhjcehust/Thread.git如果觉得不错,欢迎fork或star,实时跟踪最新开发进度~
想要获取更多干货?欢迎订阅微信公众号----软件编程之路