简体   繁体   English

std :: lock_guard构造函数实例化顺序

[英]std::lock_guard constructor instantiation order

I suppose this is more a general question about lvalue instantiation ordering. 我想这是关于左值实例化排序的更普遍的问题。

In short, is this safe?: 简而言之,这安全吗?

void func1()
{
    std::lock_guard< std::mutex > lock( mutex );
    //do some stuff in locked context
}

void func2()
{
    func1();
    std::lock_guard< std::mutex > lock( mutex );
    //do some stuff in locked context
}

I am somewhat concerned that the compiler may call the constructor of the lock_guard before calling func1 from within func2, thus causing a deadlock. 我有点担心编译器在从func2内部调用func1之前可能会调用lock_guard的构造函数,从而导致死锁。

Is it guaranteed that this is safe or do I need to do something like this: 是否保证这是安全的,还是我需要执行以下操作:

void func1()
{
    std::lock_guard< std::mutex > lock( mutex );
    //do some stuff in locked context
}

void func2()
{
    func1();

    { //lock
        std::lock_guard< std::mutex > lock( mutex );
        //do some stuff in locked context
    } //unlock
}

Those things that you're describing (the function call and the instantiation of the lock) are known as full-expressions in the standard. 您正在描述的那些东西(函数调用和锁的实例化)在标准中称为完整表达式。

As per C++11 1.9 Program execution /14 (same location and text in C++14 , same text in C++17 4.6 Program execution /16 ): 按照C++11 1.9 Program execution /14C++14相同的位置和文本, C++17 4.6 Program execution /16相同的文本):

Every value computation and side effect associated with a full-expression is sequenced before every value computation and side effect associated with the next full-expression to be evaluated. 在与要评估的下一个完整表达式关联的每个值计算和副作用之前,对与一个完整表达式关联的每个值计算和副作用进行排序。

There are cases where seemingly sequential operations can be indeterminately sequenced, but this is not one of them. 某些情况下,看似顺序的操作可以不确定地排序,但这不是其中一种。


As an aside, if you're worried about the possibility that a single thread of execution may attempt to re-acquire the same mutex twice, that's a situation where you may find recursive_mutex coming in handy. 顺便说一句,如果您担心单个执行线程可能尝试两次重新获取同一互斥锁的可能性,那么您可能会发现recursive_mutex派上用场。


As a further aside, on your comment asking about C++98 and C++03, threads were only introduced in C++11. 作为一不谈,您的评论询问C ++ 98和C ++ 03线程C ++ 11只推出。 Before then, C++ still used the concept of sequence points as per C. 在此之前,C ++仍按照C使用顺序点的概念。

In C++98 1.9 Program execution /16 and C++03 1.9 Program execution /16 , you'll find similar wording: C++98 1.9 Program execution /16C++03 1.9 Program execution /16 ,您会发现类似的措辞:

There is a sequence point at the completion of evaluation of each full-expression. 每个完整表达式的评估完成时都有一个序列点。

Just some additional notes to @paxdiablo's answer. 只是@paxdiablo答案的一些附加说明。 Generally, execution of a resulting program on a particular architecture must have the same effect as is written in the source code according to C++ Standard. 通常,在特定体系结构上执行结果程序必须具有与根据C ++标准在源代码中编写的效果相同的效果。 Due to optimizations, both compiler and CPU is allowed to generate and execute instructions in different order than the order that matches source code. 由于优化,允许编译器和CPU 生成和执行指令的顺序与匹配源代码的顺序不同

However, when multithreaded synchronization constructs are used (such as mutexes and atomic memory operations), such reordering must not happen (if not relaxed by programmer explicitly). 但是,当使用多线程同步结构 (例如互斥锁和原子内存操作)时, 这种重新排序一定不会发生 (如果程序员没有明确放松的话)。 Otherwise, multithreaded programming would not be feasible at all. 否则,多线程编程将根本不可行。

Compiler knows that it should not reorder instructions if it sees such code. 编译器知道,如果看到这样的代码,则不应重新排序指令。 On a CPU level, there are memory barriers for this task. 在CPU级别,此任务存在内存障碍。

Therefore, if you lock a mutex, you can be sure that the code written above has already completed. 因此,如果锁定互斥锁,则可以确保上面编写的代码已经完成。 This is generic multithreading concept, so I strongly believe it is valid for C++ as well. 这是通用的多线程概念,因此我坚信它也适用于C ++。 Please, correct me if I am wrong. 请改正我,如果我错了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM