【问题标题】:Check wheter atomic ptr is not initialized in gcc 4.4.7 (without nullptr)检查 gcc 4.4.7 中是否未初始化 atomic ptr(没有 nullptr)
【发布时间】:2020-06-22 12:49:52
【问题描述】:

在将单例类重构为线程安全 (fallowing Herb Sutter advice how to write proper double-check locking) 期间,我遇到了我的编译器版本(带有 --std=c++0x 标志的 gcc 4.4.7)支持原子但不支持 nullptr 的问题.

当前代码

class SingletonClass {
   public:
SingletonClass* getInstance() {
    if (instance == NULL) {
        instance == new SingletonClass();
    }
    return instance;
}

   private:
SingletonClass() = default;
~SingletonClass() = default;

static SingletonClass* instance;};

我想要达到的目标

#include <cstdatomic>
#include <mutex>

class SingletonClass {
   public:
SingletonClass* getInstance() {
    if (instance == NULL) {
        std::lock_guard<std::mutex> lock (m);
        if(instance == NULL){
           instance = new SingletonClass();
        }
    }
    return instance;
}

   private:
 SingletonClass() = default;
~SingletonClass() = default;

static std::atomic<SingletonClass*> instance;
static std::mutex m;
};

但这给了我一个错误,说没有用于将原子 ptr 与 NULL 进行比较的运算符

main.cpp: In member function ‘SingletonClass* SingletonClass::getInstance()’:
main.cpp:7: error: ambiguous overload for ‘operator==’ in ‘SingletonClass::instance == 0l’
main.cpp:7: note: candidates are: operator==(void*, void*) <built-in>
main.cpp:7: note:                 operator==(SingletonClass*, SingletonClass*) <built-in>

由于我无法将实例 ptr 与 NULL 或使用 nullptr 进行比较,我该如何解决它并检查它是否已初始化?

【问题讨论】:

  • 工具链依赖是一回事,但可以肯定的是,你能确认你被 4.4.7 卡住了吗?
  • 是的,那是我无能为力的东西
  • 如果你将NULL 明确地转换为void* 或SingletonClass* 会发生什么,比如if(instance == dynamic_cast&lt;SingletonClass*&gt;(NULL))
  • 错误:不能 dynamic_cast ‘0l’(‘long int’类型)到类型‘class SingletonClass*’(源不是指针)
  • 错误:不能将'0l'('long int'类型)动态转换为'void*'类型(源不是指针)

标签: c++ c++11 gcc gcc4


【解决方案1】:

您可以使用指针到布尔的隐式转换:

SingletonClass* getInstance() {
    if (instance.load()) {
        std::lock_guard<std::mutex> lock (m);
        if(instance.load()){
           instance.store(new SingletonClass());
        }
    }
    return instance;
}

See it online

请注意,从 std::atomic&lt;SingletonClass*&gt; 到 SingletonClass* 的隐式转换是可能的,但在这种情况下是不明确的。此外,分配本身不明确,因此添加了 store() 调用。


然而,也许解决方案更简单——你为什么需要std::atomic?你已经锁定了对存储指针的访问,所以你是安全的:

#include <mutex>

class SingletonClass {
public:
    SingletonClass* getInstance() {
        std::lock_guard<std::mutex> lock (m);
        if (instance == NULL) {
            instance = new SingletonClass();
        }
        return instance;
    }

private:
    SingletonClass() = default;
    ~SingletonClass() = default;

    static SingletonClass* instance;
    static std::mutex m;
};

std::atomic 用于无锁访问(或至少“隐藏锁”访问)。我想不出同时使用这两种方法的理由。

这里非常需要互斥锁 - 你想将整个函数锁定为临界区,否则两个线程可能会创建两个单例对象,而其中一个会被泄露。

【讨论】:

  • 我实际上同意@Yksisarvinen 的观点。一旦你有了锁,atomic 就不需要了,只会让事情复杂化。
【解决方案2】:

编辑:我认为上面 Yksisarvinen 的回答更好。你已经有锁了,不要再打扰了。在下面留下我的旧答案。

我不确定具体的 GCC 版本,但如果 &lt;atomic&gt; 存在,理论上应该可以:

SingletonClass* getInstance() {
    if (instance.load() == NULL) {
        std::lock_guard<std::mutex> lock (m);
        if(instance.load() == NULL){
            instance = new SingletonClass();
        }
    }
    return instance;
}

根据the documentation,load() 应该给你你想要的东西,指针本身要比较,应该使用 NULL。

祝旧编译器好运。由于客户的要求,我有时也不得不这样做。

【讨论】:

  • 我的回答建议直接将隐式转换为布尔值,但你的 works just as well 。分配存在问题,但可以通过store() 调用轻松解决
  • 非常感谢,这正是我要找的!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-08-19
  • 1970-01-01
  • 1970-01-01
  • 2011-10-12
  • 2015-05-23
  • 2019-01-25
  • 2022-11-12
相关资源
最近更新 更多