最近在写代码时发现了一个很奇怪的现象,单例模式生成的单例实例在同一进程中出现了多次。在此记录一下。

下面是我复现的代码,也可以直接在我的仓库进行下载

gitee

git clone https://gitee.com/little-sweet-cookie/singleton_so_test.git

代码包括五个代码文件和一个 makefile 文件

  • handler.h
  • main.cc
  • service_a.cc
  • service_b.cc
  • singleton.h
  • makefile

需要的单例实例,使用单例模板实现单例模式

// handler.h
#ifndef HANDLER_H
#define HANDLER_H
#include "singleton.h"
#include <iostream>
class Handler  {
public:
    void show()
    {
        std::cout << "Handler::instance " << (long long)this << std::endl;
    }
};
#endif // !HANDLER_H

单例模板

// singleton.h
#ifndef SINGLETON_H
#define SINGLETON_H
#include <memory>
template<typename T>
class Singleton
{
public:
    static std::shared_ptr<T> GetInstance()
    {
        if (instance == nullptr) {
            instance = std::make_shared<T>();
        }
        return instance;
    }
    Singleton(T&&) = delete;
    Singleton(const T&) = delete;
    void operator= (const T&) = delete;
protected:
    Singleton() = default;
    virtual ~Singleton() = default;
    static std::shared_ptr<T> instance;
};
template<typename T>
std::shared_ptr<T> Singleton<T>::instance;
#endif // !SINGLETON_H

业务 A

// service_a.cc
#include <iostream>
#include "handler.h"
#include "singleton.h"
extern "C" {
void show_service_a()
{
    Singleton<Handler>::GetInstance()->show();
    std::cout << "aaa" << std::endl;
} 
}

业务 B

// service_b.cc
#include <iostream>
#include "handler.h"
#include "singleton.h"
extern "C" {
void show_service_b()
{
    Singleton<Handler>::GetInstance()->show();
    std::cout << "bbb" << std::endl;
}
}

主函数

// main.cc
#include <dlfcn.h> 
#include <iostream>
#include "handler.h"
void show_main()
{
    Singleton<Handler>::GetInstance()->show();
    std::cout << "main" << std::endl;
}
int main()
{
    show_main();
    void * handle;
    using func = void (*)();
    handle = dlopen("lib_service_a.so", RTLD_LAZY);
    func show_service_a = (func)dlsym(handle, "show_service_a");  
    show_service_a();
    
    handle = dlopen("lib_service_b.so", RTLD_LAZY);
    func show_service_b = (func)dlsym(handle, "show_service_b");  
    show_service_b();
    return 0;
}

Makefile 文件

// makefile
service_a_so:service_a.cc
	g++ -fPIC -shared service_a.cc -o lib_service_a.so
service_b_so:service_b.cc
	g++ -fPIC -shared service_b.cc -o lib_service_b.so
main_so:main.cc
	g++ -fPIC -shared main.cc -o lib_main.so
clean:
	rm -f main.out lib_main.so
	rm -f lib_service_a.so
	rm -f lib_service_b.so
all:clean service_a_so service_b_so main.cc
	g++ main.cc -o main.out -Wl,-rpath=./
	./main.out
all_so:clean service_a_so service_b_so main_so
		g++ lib_main.so -o main.out -Wl,-rpath=./
	./main.out

诡异现象

  1. 当我使用 make all 时,结果如下
    cookie@cookie-VirtualBox:~/repo/test_singleton$ make all
    rm -f main.out lib_main.so
    rm -f lib_service_a.so
    rm -f lib_service_b.so
    g++ -fPIC -shared service_a.cc -o lib_service_a.so
    g++ -fPIC -shared service_b.cc -o lib_service_b.so
    g++ main.cc -o main.out -Wl,-rpath=./
    ./main.out
    Handler::instance 102966796923584
    main
    Handler::instance 102966796926512
    aaa
    Handler::instance 102966796926512
    bbb
    cookie@cookie-VirtualBox:~/repo/test_singleton$
  2. 当我使用 make all_so 时,结果如下
    rm -f main.out lib_main.so
    rm -f lib_service_a.so
    rm -f lib_service_b.so
    g++ -fPIC -shared service_a.cc -o lib_service_a.so
    g++ -fPIC -shared service_b.cc -o lib_service_b.so
    g++ -fPIC -shared main.cc -o lib_main.so
    g++ lib_main.so -o main.out -Wl,-rpath=./
    ./main.out
    Handler::instance 94236187448000
    main
    Handler::instance 94236187448000
    aaa
    Handler::instance 94236187448000
    bbb
    cookie@cookie-VirtualBox:~/repo/test_singleton$

可以看到, make all 时,会生成两个不同的单例,业务 A 与 业务 B 为同一个实例,main 为另一个实例。
而使用 make all_so 时,所有 so 中的单例都是同一个实例。

更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

小王学长 微信支付

微信支付

小王学长 支付宝

支付宝

小王学长 QQ支付

QQ支付