这个问题起源于以前给客户端写的一个log模块,然后里面为了线程安全且多线程下不互相写乱,并且因为这些系统基本都用比较高版本的编译器,都支持C++11了,所以就用了C++11的TLS功能。

但是Android的默认std库并不是libstdc++或者libc++,而是Bionic。IOS不知道是什么版本的标准库都不支持thread_local的关键字。 这个之前写过一个记录提到过 Android NDK undefined reference to ___tls_get_addr 错误。如果使用这个关键字,链接的时候会报错说找不到符号。

当时梅花太多时间,而是在这两个环境下直接用了加锁的方式。但是我们开发在Windows上,实际发布产品的时候是在Android和IOS上,这么做也就意味着开发时性能高过发布的代码。这显然不够美好,所以这两天做底层优化就顺带解决了一下。

解决方法也很简单,这两种系统虽然不支持C++11的TLS关键字,但是它们支持pthread规范啊。那么就可以这种情况直接用pthread来处理。(如果以后需要适配Windows Phone系统,并且又不支持的话再想其他办法吧)。 简化的代码如下:

#if defined(THREAD_TLS_ENABLED) && 1 == THREAD_TLS_ENABLED
namespace util {
    namespace log {
        namespace detail {
            char *get_log_tls_buffer() {
                static THREAD_TLS char ret[LOG_WRAPPER_MAX_SIZE_PER_LINE];
                return ret;
            }
        }
    }
}
#else

#include <pthread.h>
namespace util {
    namespace log {
        namespace detail {
            static pthread_once_t gt_get_log_tls_once = PTHREAD_ONCE_INIT;
            static pthread_key_t gt_get_log_tls_key;

            static void dtor_pthread_get_log_tls(void *p) {
                char *buffer_block = reinterpret_cast<char *>(p);
                if (NULL != buffer_block) {
                    delete[] buffer_block;
                }
            }

            static void init_pthread_get_log_tls() { (void)pthread_key_create(&gt_get_log_tls_key, dtor_pthread_get_log_tls); }

            char *get_log_tls_buffer() {
                (void)pthread_once(&gt_get_log_tls_once, init_pthread_get_log_tls);
                char *buffer_block = reinterpret_cast<char *>(pthread_getspecific(gt_get_log_tls_key));
                if (NULL == buffer_block) {
                    buffer_block = new char[LOG_WRAPPER_MAX_SIZE_PER_LINE];
                    pthread_setspecific(gt_get_log_tls_key, buffer_block);
                }
                return buffer_block;
            }
        }
    }
}

#endif

// 然后后面需要用缓冲区的时候用get_log_tls_buffer()函数获取

完整代码见: https://github.com/atframework/atframe_utils/blob/master/src/log/log_wrapper.cpp