std::lock_guard<std::mutex> 和 if constexpr 块的问题

问题描述 投票:0回答:2

有一个类模板

Foo<T>
。对于某些特定类型,函数应该使用
lock_guard
。 这是示例代码:

#include <type_traits>
#include <mutex>
#include <vector>

template<typename T> 
class Foo {
public:
    void do_something(int k) {

        if constexpr(std::is_same_v<T, NeedMutexType>) {
            std::lock_guard<std::mutex> lock(mtx_);
        }

        resource_.push_back(k);
        // code for task with resource_ ...
    }

private:
    std::mutex mtx_;
    std::vector<int> resource_;
};

std::lock_guard
将在 if constexpr 范围的末尾被破坏。 (如有不妥,请指正。)

为了处理这个问题,我可以将下面带有

resource_
的任务代码复制到 if constexpr 范围内,或者只使用原始的
std::mutex
,例如
mtx_.lock()
&
mtx_.unlock()
代替。

有什么方法可以用

std::lock_guard
处理这个问题吗?谢谢。

c++ templates mutex lock-guard
2个回答
3
投票

也许 std::conditional 可以来拯救这里,如果你需要经常做这种事情。

template<class Mutex>
struct FakeLockGuard { FakeLockGuard(Mutex&){} };

template<typename T, class Mutex = std::mutex>
using OptionalLock = typename std::conditional<
    std::is_same_v<T, NeedMutexType>,
    std::lock_guard<Mutex>,
    FakeLockGuard<Mutex>>::type;

这里我们定义了一个什么都不做的类模板,其构造方式与

std::lock_guard
相同。然后,我们将其与
std::conditional
结合使用,根据类型检查的结果选择
std::lock_guard
FakeLockGuard

现在您可以按如下方式使用它:

template<typename T> 
class Foo {
public:
    void do_something(int k)
    {
        OptionalLock<T> lock(mtx_);
        resource_.push_back(k);
        // ...
    }

private:
    std::mutex mtx_;
    std::vector<int> resource_;
};

您可以通过在

FakeLockGuard
构造函数中设置断点或使其输出一些内容来轻松验证它是否有效。

这就是你如何让它在编译时工作。但是我认为正如您已经提到的那样,您可以简单地构造一个

unique_lock
然后有条件地锁定它。这样做的好处是对于必须使用您的代码的任何人来说都更加清晰。最后,就看你觉得哪个最合适了。


2
投票

只需在解锁状态下构建锁,然后再锁定:

template<typename T> 
class Foo {
public:
    void do_something(int k) {
        std::unique_lock<std::mutex> lock(mutex_, std::defer_lock);
        if constexpr(std::is_same_v<T, NeedMutexType>) {
            lock.lock();
        }

        resource_.push_back(k);
        // code for task with resource_ ...
    }

private:
    std::mutex mtx_;
    std::vector<int> resource_;
}

请注意,您需要为此使用

std::unique_lock
,因为
std::lock_guard
无法解锁

© www.soinside.com 2019 - 2024. All rights reserved.