C++中线程级资源自动释放
Updated:
我们常常在代码通过类的生命周期来管理资源释放,构造函数的时候申请资源,析构函数的时候释放资源,这样可以减少程序员自动释放资源的工作,避免内存泄露。而有些场景,一个资源是线程级别共享的,线程结束后才释放,对于这种场景,可以利用Thread Local Storage机制,因为在C++中,线程局部变量的析构函数会随着线程的结束而调用
函数级
先复习一下函数级资源释。对于C++,程序员可以申请栈上面的资源,随着函数结束,资源被释放,对应的析构函数马上被调用,这个生命周期机制,能让程序员在构造和析构函数里做一些资源管理的事情
实例: 局部锁
函数级资源释放应用最多的就是局部锁,在构造函数获取锁,在析构的时候释放锁
template <class Lockable> |
调用代码如下:
void func() |
线程级
相对于函数级别的资源释放,线程级别通常是一个线程局部对象,随着线程的结束,该对象会自动调用析构函数,跟函数级思路一致
实例:Qt中JniEnv实现
在Jni中,获取JNIEnv时,在使用前要调用AttachCurrentThread,使用后要调用DetachCurrentThread,否则线程无法正常退出,这就给程序员比较大压力,我们需要想一种方法来封装这个操作,Qt中的全局JniEnv实现给了我们一种思路
如下面代码所示,有一个全局静态变量QJNIEnvironmentPrivateTLS,存放在QThreadStorage中,表示是线程局部变量,它的析构函数是执行DetachCurrentThread操作,表示在线程退出时会调用这个操作。其中QThreadStorage的实现类似Java的ThreadLocal,是实现线程局部变量的关键
class QJNIEnvironmentPrivateTLS |
QJNIEnvironmentPrivate在构造函数中会获取JNIEnv,如果发现没有调用过AttachCurrentThread则马上Attach一下,
每个线程在AttachCurrentThread时会在线程局部变量中初始化一个QJNIEnvironmentPrivateTLS实例,这样可以保证在线程退出时会调用相应的DetachCurrentThread操作
static const char qJniThreadName[] = "QtThread"; |
QJNIEnvironmentPrivate还重载了->方法,这样使用者就可以通过QJNIEnvironmentPrivate来使用JniEnv,而不用考虑AttachCurrentThread和DetachCurrentThread操作
JNIEnv *QJNIEnvironmentPrivate::operator->() |
调用代码如下:
//other Jni module |
如果线程只执行这个jniTest函数,随着函数执行,线程结束,QtAndroidPrivate::javaVM()->DetachCurrentThread()会被自动调用
结论
如果不采用线程级资源管理的方式,就会在代码中布满了一对对AttachCurrentThread方法DetachCurrentThread,十分容易出Bug,对JNIEnv的封装也让其他Jni模块可以方便的使用Jni功能