singleton_on_pthread_once.h 2.58 KB
Newer Older
gejun's avatar
gejun committed
1
// Copyright (c) 2016 Baidu, Inc.
gejun's avatar
gejun committed
2
// 
gejun's avatar
gejun committed
3 4 5 6 7 8 9 10 11 12 13 14
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
 
gejun's avatar
gejun committed
15 16 17 18 19 20 21
// Author: Ge,Jun (gejun@baidu.com)
// Date: Thu Dec 15 14:37:39 CST 2016

#ifndef BASE_MEMORY_SINGLETON_ON_PTHREAD_ONCE_H
#define BASE_MEMORY_SINGLETON_ON_PTHREAD_ONCE_H

#include <pthread.h>
22
#include "butil/atomicops.h"
gejun's avatar
gejun committed
23

24
namespace butil {
gejun's avatar
gejun committed
25

26 27
template <typename T> class GetLeakySingleton {
public:
28
    static butil::subtle::AtomicWord g_leaky_singleton_untyped;
gejun's avatar
gejun committed
29 30 31 32
    static pthread_once_t g_create_leaky_singleton_once;
    static void create_leaky_singleton();
};
template <typename T>
33
butil::subtle::AtomicWord GetLeakySingleton<T>::g_leaky_singleton_untyped = 0;
gejun's avatar
gejun committed
34 35 36 37 38 39 40

template <typename T>
pthread_once_t GetLeakySingleton<T>::g_create_leaky_singleton_once = PTHREAD_ONCE_INIT;

template <typename T>
void GetLeakySingleton<T>::create_leaky_singleton() {
    T* obj = new T;
41
    butil::subtle::Release_Store(
gejun's avatar
gejun committed
42
        &g_leaky_singleton_untyped,
43
        reinterpret_cast<butil::subtle::AtomicWord>(obj));
gejun's avatar
gejun committed
44 45 46 47 48 49 50 51 52
}

// To get a never-deleted singleton of a type T, just call get_leaky_singleton<T>().
// Most daemon threads or objects that need to be always-on can be created by
// this function.
// This function can be called safely before main() w/o initialization issues of
// global variables.
template <typename T>
inline T* get_leaky_singleton() {
53
    const butil::subtle::AtomicWord value = butil::subtle::Acquire_Load(
gejun's avatar
gejun committed
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
        &GetLeakySingleton<T>::g_leaky_singleton_untyped);
    if (value) {
        return reinterpret_cast<T*>(value);
    }
    pthread_once(&GetLeakySingleton<T>::g_create_leaky_singleton_once,
                 GetLeakySingleton<T>::create_leaky_singleton);
    return reinterpret_cast<T*>(
        GetLeakySingleton<T>::g_leaky_singleton_untyped);
}

// True(non-NULL) if the singleton is created.
// The returned object (if not NULL) can be used directly.
template <typename T>
inline T* has_leaky_singleton() {
    return reinterpret_cast<T*>(
69
        butil::subtle::Acquire_Load(
gejun's avatar
gejun committed
70 71 72
            &GetLeakySingleton<T>::g_leaky_singleton_untyped));
}

73
} // namespace butil
gejun's avatar
gejun committed
74 75

#endif // BASE_MEMORY_SINGLETON_ON_PTHREAD_ONCE_H