博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
利用C++对象的生命周期让你的代码看起来更简洁高效
阅读量:5952 次
发布时间:2019-06-19

本文共 4963 字,大约阅读时间需要 16 分钟。

在native用c++ coding的时候,多线程并发是很常见的情况,这个时候需要用锁来管理公共资源;还有一种常见情况是,在debug的时候需要关注一个函数进来和出去的信息。

这两种情况会增加一些额外的代码,可能使你的代码看起来不是那么美好,而且在函数比较大且出口比较多的时候还容易忘记在某个出口进行操作,如果只是打印信息只是统计不出来,如果是忘记了释放锁,那这个线程就死锁了会造成更多稳定性问题。

通过利用C++对象的生命周期可以让你的代码变的更简洁美好而且高效,android系统源代码里大量的使用了类似的设计。

1.多线程并发是很常见的情况,这个时候需要用锁来管理公共资源

假如一个函数大概是这样的,我们要通过锁来锁住里边的资源,每一个出口都要加上pthread_mutex_unclok,是不是看上去不爽,而且还容易忘。

int func1() {pthread_mutex_lock();if(con1) {    Res.value=1;    pthread_mutex_unlock();    return Res;
}Res.op1();Res.op2();if(con2){    Res.op3();    pthread_mutex_unlock();    return Res;}...Res.op18()return Res;pthread_mutex_unlock();}

android源码里提供了一个Mutex完美的解决了这个问题,使用Mutex后函数变成了这样的。

是不是简洁了好多,还不用担心忘记在哪个出口释放。

int func1() {Mutex::Autolock lock(mLock);if(con1) {    Res.value=1;    return Res;
}Res.op1();Res.op2();if(con2){    Res.op3();    return Res;}...Res.op18()return Res;}

其实原理很简单,利用了lock这个对象的生命周期,和它的构造函数和析构函数。func1函数进来的时候创建了Mutex::Autolock类的临时变量对象lock,会执行构造函数在构造函数里lock住mLock,当func1函数返回退出的时候无论在哪个出口,函数调用栈结束的最后,临时变量对象lock的生命周期结束,并对对象进行回收执行析构函数,在析构函数里unlock mLock,完成整个锁和解锁的过程。

不过在早期的ndk里并没有提供这个api,后来的版本里有了,所以为了程序的兼容性,可以自己实现 Mutex和Autolock,就是拷贝android的源代码了,100行都不到。下边是我在normandie项目里拷贝的源代码,熟悉c++语法的话很容易理解。

/** AutoMutex from AOSP*//#ifndef _NMD_UTILS_AUTOMUTEX_H/#define _NMD_UTILS_AUTOMUTEX_H/#include 
/#include
/#include
/#include
/#include
/#include
/* Simple mutex class. The implementation is system-dependent.* The mutex must be unlocked by the thread that locked it. They are not* recursive, i.e. the same thread can't lock it multiple times.*/class NmdMutex {public: enum { PRIVATE = 0, SHARED = 1 }; NmdMutex(); NmdMutex(const char* name); NmdMutex(int type, const char* name = NULL); ~NmdMutex(); // lock or unlock the mutex status_t lock(); void unlock(); // lock if possible; returns 0 on success, error otherwise status_t tryLock(); // lock the mutex, but don't wait longer than timeoutMilliseconds. // Returns 0 on success, TIMED_OUT for failure due to timeout expiration. // // OSX doesn't have pthread_mutex_timedlock() or equivalent. To keep // capabilities consistent across host OSes, this method is only available // when building Android binaries. status_t timedLock(nsecs_t timeoutMilliseconds); // Manages the mutex automatically. It'll be locked when Autolock is // constructed and released when Autolock goes out of scope. class Autolock { public: inline Autolock(NmdMutex& mutex) : mLock(mutex) { mLock.lock(); } inline Autolock(NmdMutex* mutex) : mLock(*mutex) { mLock.lock(); } inline ~Autolock() { mLock.unlock(); } private: NmdMutex& mLock; };private: // A mutex cannot be copied NmdMutex(const NmdMutex&); NmdMutex& operator = (const NmdMutex&); pthread_mutex_t mMutex;};// ---------------------------------------------------------------------------inline NmdMutex::NmdMutex() { pthread_mutex_init(&mMutex, NULL);}inline NmdMutex::NmdMutex(__attribute__((unused)) const char* name) { pthread_mutex_init(&mMutex, NULL);}inline NmdMutex::NmdMutex(int type, __attribute__((unused)) const char* name) { if (type == SHARED) { pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED); pthread_mutex_init(&mMutex, &attr); pthread_mutexattr_destroy(&attr); } else { pthread_mutex_init(&mMutex, NULL); }}inline NmdMutex::~NmdMutex() { pthread_mutex_destroy(&mMutex);}inline status_t NmdMutex::lock() { return -pthread_mutex_lock(&mMutex);}inline void NmdMutex::unlock() { pthread_mutex_unlock(&mMutex);}inline status_t NmdMutex::tryLock() { return -pthread_mutex_trylock(&mMutex);}inline status_t NmdMutex::timedLock(nsecs_t timeoutNs) { const struct timespec ts = { /* .tv_sec = */ static_cast
(timeoutNs / 1000000000), /* .tv_nsec = */ static_cast
(timeoutNs % 1000000000), }; return -pthread_mutex_timedlock(&mMutex, &ts);}// ---------------------------------------------------------------------------/* * Automatic mutex. Declare one of these at the top of a function. * When the function returns, it will go out of scope, and release the* mutex.*/typedef NmdMutex::Autolock NmdAutoMutex;/#endif // _NMD_UTILS_AUTOMUTEX_H

2.还有一种常见情况是,在debug的时候需要关注一个函数进来和出去的信息

比如我想统计一下某个函数的耗时,或者想观察它是不是正常退出了。一般都会这么写。是不是看着有点上火。

void func2() {log(“in”);do1();if(con1) {    do2();    log(“out”);    return;}if(con2) {    do3();    log(“out”);    return;}if(con3) {    do4();    log(“out”);    return;}if(con4) {    do5();    log(“out”);    return;}log(“out”);}

还可以这么写

void func2() {TimeCacl cacl(“func2”);do1();if(con1) {    do2();    return;}if(con2) {    do3();    return;}if(con3) {    do4();    return;}if(con4) {    do5();    return;}}

只需要定义一个类

class TimeCacl {public:    TimeCacl(char* func_name) {        mFuncName.append(func_name);        log(“%s in”, mFuncName.c_str());    }    ~TimeCacl() {        log(“%s out”, mFuncName.c_str());    }private:    String8 mFuncName;}

跟Mutex::Autolock异曲同工,都是利用了对象的生命周期来达成目的的。

转载地址:http://nnoxx.baihongyu.com/

你可能感兴趣的文章
Vuex学习
查看>>
bootstrap - navbar
查看>>
切图崽的自我修养-[ES6] 编程风格规范
查看>>
[React Native Android 安利系列]样式与布局的书写
查看>>
利用dxflib读写cad文件
查看>>
服务器迁移小记
查看>>
FastDFS存储服务器部署
查看>>
Android — 创建和修改 Fragment 的方法及相关注意事项
查看>>
流程控制: jQ Deferred 与 ES6 Promise 使用新手向入坑!
查看>>
swift基础之_swift调用OC/OC调用swift
查看>>
Devexpress 15.1.8 Breaking Changes
查看>>
推荐JS插件:imagesLoaded,监测图片加载情况并提供相应的事件(加载成功/失败)...
查看>>
Java B2B2C多用户商城 springcloud架构- common-service 项目构建过程(七)
查看>>
杨老师课堂之ArrayList集合常用方法解析
查看>>
ElasticSearch Client详解
查看>>
新零售讲堂之时代下的传统零售业,何去何从?
查看>>
c++读取和写入TXT文件的整理
查看>>
深入动态人脸识别小场景应用,2019年或将迎来爆发期
查看>>
Ionic2 下处理 Android 设备下返回按钮的事件
查看>>
linux基础--grep以及模式正则表达式
查看>>