Visual Studio的std :: mutex实现是不正确的还是只是"较弱"比其他stl实现?

时间:2018-03-05 02:16:17

标签: c++ multithreading visual-c++ mutex

我对互斥体的理解是它有两个保证:

  • 互相排斥
  • 给定一个n,它将保证一个等待的线程将在其他线程排除"切入行中后获得锁定。

我知道信号量必须有第二个保证,我希望互斥量也应该有它,因为所有平台相关的互斥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引起的,但是关键部分文档(12)表示&#34; ...但是,系统对所有线程都是公平的#34 ;.我认为这相当于第二个保证。

另一位评论者表示,对锁的争论太多了。这就是重点,如果没有争用,则不需要第二次担保。

Zan Lynx的评论可能适用,因为我在(现代)AMD机器上运行,但即便如此,互斥锁应该足够高,操作系统处理已知的硬件功能。

有人说调试模式&#34;如果原始问题没有出现在示例的发布模式中,我们就不能说太多了。&#34;这基本上是错误的。虽然这是多线程的,因此不确定,但程序在调试和发布(优化与不优化)中的结果应该是一致的。如果它不是,则编译器是错误的(如果数据竞争空闲则顺序一致)。由于所有共享变量都受到保护,因此没有数据争用(join_counter和erratic_counter由join()隐式保护。)

0 个答案:

没有答案