全球状态互斥与锁定

时间:2018-11-16 16:22:58

标签: c++ mutex raii

这个问题不是glfw特有的,但是它可以很好地描述我的意思。在glfw中,为了开始使用任何函数,我们需要调用glfwInit(),而当我们不再需要使用它们时,我们需要调用glfwTerminate(),我一直在尝试找到一种将其包装在RAII类上的方法。 ,而且我发现了两种有用的方法,但是我不确定每种方法的优缺点。在所有这些中,我都省略了错误检查之类的内容,因为它们不会对示例进行太多更改。

1:使用类似锁的类

我的第一个想法是创建一个类似锁的类,该类在生命周期的开始时调用glfwInit(),在结束时调用glfwTerminate(),如下所示:

struct GLFWLock
{
     GLFWLock() { glfwInit(); }
    ~GLFWLock() { glfwTerminate(); }
}

我意识到,如果创建了两个这样的类,那么glfwInit和glfwTerminate将被调用两次,因此我添加了一个ref计数器,除了使它成为线程安全的和可能的其他线程之外,我觉得这是一个相当完整的解决方案,但本质上是同一件事:

struct GLFWLock
{
    static size_t ref_count; /* = 0 in .cpp */

     GLFWLock() { if ( ref_count == 0 ) { glfwInit(); } ref_count++; }
    ~GLFWLock() { ref_count--; if ( ref_count == 0 ) { glfwTerminate(); } }
}

2:使用类似Mutex的类

使用以前的模型一段时间后,我意识到它在某种程度上与带有互斥锁的std :: lock_guard相同,所以我认为我可以制作一个互斥锁类并让用户在任何时候都进行一次lock_guard他们需要使用glfw,而不是仅仅提供锁。

我最终想到了这个,它符合标准中的互斥锁的概念,忽略了一些正式的要求,只关注std :: lock_guard实际使用的内容:

struct GLFWMutex
{
    static size_t ref_count; /* = 0 in the .cpp */
    bool locked = false;

    ~GLFWMutex() { unlock(); }

    void lock() 
    {
        if ( !locked )
        {
            if ( ref_count == 0 ) { glfwInit(); }
            ref_count++;
            locked = true;
        }
    }

    void unlock()
    {
        if ( locked )
        {
            locked = false;
            ref_count--;
            if ( ref_count == 0 ) { glfwTerminate(); }
        }
    }
};

然后在需要时将其与std :: lock_guard一起使用,就像普通的互斥锁一样。

我可以看到使用类似锁的类比您键入的要少,因为您不必声明互斥锁和保护,但是类似互斥锁的类会更有用吗?可能在添加了更多的成员函数(例如try_lock(),owns_lock()和其他函数)之后?还是有更好的解决方案来封装这种行为?

编辑1:

我希望此共享状态的用法语法如下:

struct glfw_shared_state
{
    static size_t ref_count; /* = 0 in .cpp */

     glfw_shared_state() { if ( ref_count == 0 ) { glfwInit(); } ref_count++; }
    ~glfw_shared_state() { ref_count--; if ( ref_count == 0 ) { glfwTerminate(); } }
};

struct Game
{
    /// While this Game object is alive, I want to share the state of glfw, so it isn't terminated
    glfw_shared_state state;

    (...)
};

游戏的每个实例在ref_count处增加一个,这将使glfw在游戏的整个生命周期中都保持活动状态,基本上是shared_ptr,但用于函数而不是对象

编辑2:

对于std :: lock_guard,我的意思是这样的:

/// This has an internal ref counter for how many threads are currently locking it
/// When it first starts with 0 threads and someone locks, it calls glfwInit()
/// Then everytime some other thread locks, it just ups the ref counter
/// After every thread using it has unlocked it and it's ref counter is 0, it calls glfwTerminate()
/// So this isn't locking anyway, it's just sharing a state
glfw_mutex global_glfw_mutex;

void draw()
{
    /// Make sure glfw is alive during this draw function
    std::lock_guard lock(global_glfw_mutex);
}

这有点令人费解,但这本质上是我在原始帖子中的第二个示例中所表达的意思,我认为互斥锁和锁不适合用于此目的,但我认为注释传达了我想要代码的含义有,“锁”本质上只是一个shared_ptr

0 个答案:

没有答案