【发布时间】:2020-05-28 15:46:56
【问题描述】:
为什么我不应该从不同的线程解锁互斥锁?在 c++ 标准中,它说得很清楚:如果互斥锁当前没有被调用线程锁定,它会导致未定义的行为。但据我所知,在 Linux(Fedora 31 with GCC)上一切正常。我认真地尝试了一切,但我无法让它表现得异常。 我所要求的只是一个示例,其中从不同线程解锁互斥锁会影响某些东西,实际上是任何东西。
这是我写的一个快速测试,它是超级错误的,不应该工作,但它确实有效:
std::mutex* testEvent;
int main()
{
testEvent = new std::mutex[1000];
for(uint32_t i = 0; i < 1000; ++i) testEvent[i].lock();
std::thread threads[2000];
auto lock = [](uint32_t index) ->void { testEvent[index].lock(); assert(!testEvent[index].try_lock()); };
auto unlock = [](uint32_t index) ->void { testEvent[index].unlock(); };
for(uint32_t j = 0; j < 1000; ++j)
{
for(uint32_t i = 0; i < 1000; ++i)
{
threads[i] = std::thread(lock,i);
threads[i+1000] = std::thread(unlock,i);
}
for(uint32_t i = 0; i < 2000; ++i)
{
threads[i].join();
}
std::cout << j << std::endl;
}
delete[] testEvent;
}
【问题讨论】:
-
但据我所知,在 Linux 上一切正常(Fedora 31 with GCC) 未定义程序的结果集包含您正在寻找的结果.这是 UB 中最危险的部分,它看起来可以完美运行。
-
如果一切都按预期工作有什么问题吗? 是的。你基本上有一个活弹。它可能多年没有做任何事情,或者它可能会在你第一次发生变化时炸毁你的脸,比如在不同的机器上运行或使用不同的编译器进行编译。
-
UB 在启用优化器时往往会咬得最紧。并且不同的编译器(或相同编译器的不同版本)或不同平台上的相同编译器可能会生成不同的代码并表现不同。即使添加或删除不相关的代码也可能导致编译器改变行为,因为未定义的是整个程序,而不仅仅是包含 UB 的部分。简而言之;你只是不再对你的程序行为有任何保证,这不是你想要的情况。它是一个可以在任何时间爆炸的定时炸弹任何变化。
-
每次我发现有人这样做都是因为他们不知道他们可以通过监视器(条件变量)得到他们想要的东西。
标签: c++ linux mutex undefined-behavior