c++ - std::mutex 锁定顺序

标签 c++ multithreading locking mutex stdthread

我很少想过在两个连续的表达式之间,在函数调用和函数体第一个表达式执行之间,或者在构造函数调用和初始化器执行之间发生了什么。然后我开始阅读有关并发的内容...

1.) 在对 std::thread 构造函数的两次连续调用中,具有相同的可调用对象(例如函数、仿函数、lambda),其主体以 std::lock_guard 开头 使用相同的std::mutex 对象初始化,标准是否保证与第一个thread 构造函数调用对应的线程首先执行受锁保护的代码?

2.) 如果标准没有做出保证,那么第二个thread构造函数调用对应的线程是否有理论上或实践上的可能性先执行 protected 代码? (例如,在执行初始化程序或第一个 thread 构造函数调用的主体期间系统负载过重)

这是一个全局的 std::mutex 对象 m 和一个初始化为 的全局 unsigned num 1。函数 foo 主体的左大括号 {std::lock_guard 之间只有空格。在main中,有两个std::threadt1t2t1 首先调用线程构造函数。 t2 第二个调用线程构造函数。每个线程都是用指向 foo 的指针构造的。 t1 使用 unsigned 参数 1 调用 foot2 使用 unsigned 参数 2 调用 foo。根据哪个线程首先锁定 mutexnum 的值将是 43两个线程都执行了受锁保护的代码。如果 t1 击败 t2 获得锁,num 将等于 4。否则,num 将等于 3。我通过循环并在每个循环结束时将 num 重置为 1 进行了 100,000 次试验。 (据我所知,结果不会也不应该取决于哪个线程首先被 join()ed。)

#include <thread>
#include <mutex>
#include <iostream>

std::mutex m;
unsigned short num = 1;

void foo(unsigned short par) {
    std::lock_guard<std::mutex> guard(m);
    if (1 == num)
        num += par;
    else
        num *= par;
}

int main() {
    unsigned count = 0;
    for (unsigned i = 0; i < 100000; ++i) {
        std::thread t1(foo, 1);
        std::thread t2(foo, 2);
        t1.join();
        t2.join();
        if (4 == num) {
            ++count;
        }
        num = 1;
    }
    std::cout << count << std::endl;
}

最后,count 等于 100000,所以 t1 每次都赢得比赛。但这些试验并不能证明什么。

3.) 标准要求“首先调用 thread 构造函数”是否总是意味着“首先调用传递给 thread 构造函数的可调用对象”?

4.) 标准要求“首先调用传递给线程构造函数的可调用对象”是否总是意味着“首先锁定互斥锁”;如果在可调用对象的主体中,不存在依赖于在 std::lock_guard 初始化行之前传递给可调用对象的参数的代码? (还要排除任何可调用的本地 static 变量,例如调用次数的计数器,可用于故意延迟某些调用。)

最佳答案

  1. 不,标准不保证第一个线程首先获得锁。基本上,如果您需要在线程之间强加和排序,则需要在这些线程之间进行同步。即使第一个线程先调用互斥锁函数,第二个线程也可能先获得锁。
  2. 当然。例如,在生成线程时,您的应用程序可能只有一个核心可用,如果生成线程决定在第二个线程生成后等待某事,则调度程序可能决定处理最新看到的线程,即第二个线程。即使有很多内核可用,也有很多原因使第二个线程更快。
  3. 不,为什么会这样!第一步是产生一个线程并继续。当第一个函数对象被调用时,第二个线程可以运行并调用它的函数对象。
  4. 没有。线程之间没有顺序保证,除非您自己明确强加它们,因为它们会破坏并发的目的。

关于c++ - std::mutex 锁定顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21057231/

相关文章:

c++ - SDL 无法创建 OpenGL 窗口

java - 在 Java 中以原子方式释放多个锁

Mysql 表锁别名不起作用

rest - 使用内存中的H2数据库在Grails 2.4.4中执行REST API功能测试时,表锁定超时

c++ - 为什么我在这段代码中出现编译错误?

c++ - setHeaderData 不工作 + qt

c++ - 展开可变参数模板结构

c++ - Pthread 在信号句柄中使用 pthread_cond_wait 阻塞

javascript - Node.js 的缺点?

java - 线程可以在 run() 的同步块(synchronized block)中间被中断吗?