我对互斥体的理解是它有两个保证:
我知道信号量必须有第二个保证,我希望互斥量也应该有它,因为所有平台相关的互斥apis似乎都有它,但我无法在标准中的任何地方找到它需要std ::互斥拥有它。
当我在我的机器上运行以下代码时,"不稳定"线程被"一致"线。 (没有参数编译,只有cl file.cpp和g ++ file.cpp -std = c ++ 11 -o等)
#include <thread>
#include <iostream>
#include <vector>
#include <mutex>
#define THREAD_COUNT 1
#define ITERATIONS 1'000'000
uint64_t consistent_counter = 0;
uint64_t erratic_counter = 0;
bool finish = false;
uint64_t sleep_count = 0;
std::mutex mytex;
void erratic()
{
int i = 1;
while (!finish)
{
if (i % 100 == 0)
{
++sleep_count;
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
++i;
mytex.lock();
++erratic_counter;
mytex.unlock();
}
finish = true;
}
void consistent()
{
while (!finish)
{
mytex.lock();
++consistent_counter;
for (uint64_t i = 0; i < ITERATIONS; ++i)
{
}
mytex.unlock();
}
}
int main(void)
{
std::vector<std::thread> threads;
for (int i = 0; i < THREAD_COUNT; ++i)
{
threads.emplace_back(consistent);
}
std::thread erratic_useage(erratic);
std::this_thread::sleep_for(std::chrono::seconds(10));
finish = true;
erratic_useage.join();
for (int i = 0; i < THREAD_COUNT; ++i)
{
threads[i].join();
}
std::cout << "erratic: " << erratic_counter << std::endl;
std::cout << "consistent: " << consistent_counter << std::endl;
std::cout << "sleeps: " << sleep_count << std::endl;
return 0;
}
这是我的输出:
.\test_g++.exe
erratic: 1400
consistent: 4516
sleeps: 14
.\test_vs.exe
erratic: 1
consistent: 3779
sleeps: 0
&#34; eratic&#34;尽管另一个线程获得锁3779次,线程只获得一次锁。这违反了我认为互斥锁的第二个保证。
Visual Studio Installer中报告的版本是Visual Studio Enterprise 15.5.4
一个建议是这是由使用Microsoft CRITICAL_SECTION引起的,但是关键部分文档(1,2)表示&#34; ...但是,系统对所有线程都是公平的#34 ;.我认为这相当于第二个保证。
另一位评论者表示,对锁的争论太多了。这就是重点,如果没有争用,则不需要第二次担保。
Zan Lynx的评论可能适用,因为我在(现代)AMD机器上运行,但即便如此,互斥锁应该足够高,操作系统处理已知的硬件功能。
有人说调试模式&#34;如果原始问题没有出现在示例的发布模式中,我们就不能说太多了。&#34;这基本上是错误的。虽然这是多线程的,因此不确定,但程序在调试和发布(优化与不优化)中的结果应该是一致的。如果它不是,则编译器是错误的(如果数据竞争空闲则顺序一致)。由于所有共享变量都受到保护,因此没有数据争用(join_counter和erratic_counter由join()隐式保护。)