C++ 在C+中模拟C#lock语句+;

C++ 在C+中模拟C#lock语句+;,c++,multithreading,locking,C++,Multithreading,Locking,简介:对于同步,C#提供了System.Threading.Monitor类,提供线程同步例程,如Enter()、Exit()、TryEnter()等 此外,还有一个lock语句,它确保在关键代码块离开时,锁被破坏,无论是通过正常执行流还是异常: private static readonly obj = new Object(); lock(obj) { ... } >强>问题:在C++中,为此,我们得到了RAII包装器 STD::CuxIGueGue和

简介:对于同步,C#提供了
System.Threading.Monitor
类,提供线程同步例程,如
Enter()
Exit()
TryEnter()

此外,还有一个
lock
语句,它确保在关键代码块离开时,锁被破坏,无论是通过正常执行流还是异常:

private static readonly obj = new Object();

lock(obj) {
   ...
}
<> >强>问题:在C++中,为此,我们得到了RAII包装器<代码> STD::CuxIGueGue和,不适用于Mistabor 类,而适用于实现<代码>可锁定概念的类型。然而,我认为这种方法在语法上比C语言实现的方式弱,有以下几个原因:

您使用无法重用的变量名污染了本地范围。可以通过添加新的作用域(如

  {
      std::unique_lock<std::mutex> lck{ mtx };
      ...
  }
Q:我如何在C++11/14中实现这一点?

抛开“应该这样做”不谈,下面是如何实现的:

虽然它不太一样,因为它需要一个分号,它足够接近,我觉得我可以提出它。这个纯C++14解决方案基本上只定义了启动lambda的宏,该宏将立即执行:

template<typename MTX>
struct my_lock_holder {
    MTX& mtx;
    my_lock_holder(MTX& m) : mtx{m} {}
};

template<typename MTX, typename F>
void operator+(my_lock_holder<MTX>&& h, F&& f) {
    std::lock_guard<MTX> guard{h.mtx};
    std::forward<F>(f)();
}

#define LOCK(mtx) my_lock_holder<decltype(mtx)>{mtx} + [&]
您可以看到它的构建。

我建议您:

#define UNIQUE_NAME(name) name##__COUNTER__
#define LOCK(mutex) std::lock_guard<decltype(mutex)> UNIQUE_NAME(My_Lock){ mutex };
#定义唯一的_名称(名称)名称###计数器__
#定义锁(互斥锁)std::LOCK\u guard UNIQUE\u NAME(My\u LOCK){mutex};
使用
计数器预处理器符号将生成一个您根本不关心的唯一变量名。

受StoryTeller伟大思想的启发,我认为我自己找到了一个可行的解决方案,尽管我是一个“黑客”:

模板
结构怪异锁定最终:私有标准::锁定保护{
布尔翻转;
奇怪的锁(T&m):std::锁{m},翻转{true}{}
运算符bool()noexcept{
bool old=翻转;
翻转=错误;
返老还童;
}
};
#为(奇怪的锁W_uul_u{mutex};W_ul_u;)定义锁(互斥)

好在它的结尾不需要分号。坏的是需要一个额外的
bool
,但从我在godbolt.org中看到的情况来看,编译器无论如何都优化了它。

离题,但要说的是:那些标识符(包含双下划线)。@StoryTeller A'ight,我只是想确保这个名字很晦涩,它永远不会和任何东西发生冲突。你可能应该习惯于C语言和C++完全不同的语言,而不是尝试和语言打交道。我认为
std::unique_lock lock{mtx}
非常“自然”,但是
私有静态只读obj=newobject()看起来非常复杂。为什么不需要一个宏呢?:-)@BoPersson这只是一个变量初始化,它在不同情况下看起来可能会非常不同。虽然是两种不同的语言,但我认为尝试在另一种语言中采用在一种语言中效果很好的东西并没有错。这取决于你如何使语言变得熟悉。来自Pascal的人可能会尝试
#define begin{
#define end}
来让自己感觉更自在,但很快就会放弃。这里的问题是,在锁作用域的末尾,锁不会被释放,但当包含lock(mutex)语句的作用域离开时。这肯定很有用,也很聪明,因此,全体投票。像这样的事情也可以用C++11来完成吗?@Jodocus-你知道,我认为我没有使用任何C++14的特定功能。我只是没有在C++11模式下尝试。它很可能按原样工作。
template<typename MTX>
struct my_lock_holder {
    MTX& mtx;
    my_lock_holder(MTX& m) : mtx{m} {}
};

template<typename MTX, typename F>
void operator+(my_lock_holder<MTX>&& h, F&& f) {
    std::lock_guard<MTX> guard{h.mtx};
    std::forward<F>(f)();
}

#define LOCK(mtx) my_lock_holder<decltype(mtx)>{mtx} + [&]
std::mutex mtx;
LOCK(mtx) {

}; // Note the semi-colon
#define UNIQUE_NAME(name) name##__COUNTER__
#define LOCK(mutex) std::lock_guard<decltype(mutex)> UNIQUE_NAME(My_Lock){ mutex };
template <typename T>
struct Weird_lock final : private std::lock_guard<T> {
    bool flip;
    Weird_lock(T& m) : std::lock_guard<T>{ m }, flip{ true } { }

    operator bool() noexcept {
        bool old = flip;
        flip = false;
        return old;
    }
};

#define LOCK(mutex) for(Weird_lock<decltype(mutex)> W__l__{ mutex }; W__l__;)