强制并发修改变量 (C++)
Enforce concurrent modification of a variable (C++)
我正在尝试对原子库进行单元测试(我知道原子库不适合进行单元测试,但我仍然想尝试一下)
为此,我想让 X 个并行线程递增一个计数器并计算结果值(应该是 X)。
代码如下。问题是它永远不会中断。 Counter
总是很好地以 2000 结束(见下文)。我还注意到 cout
也是作为一个整体打印的(而不是混合在一起,我记得在其他多线程 couts
中看到的)
我的问题是:为什么这不会中断?或者我怎样才能打破这种局面?
#include <iostream>
#include <thread>
#include <vector>
#include <mutex>
#include <condition_variable>
std::mutex m;
std::condition_variable cv;
bool start = false;
int Counter = 0;
void Inc() {
// Wait until test says start
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, [] {return start; });
std::cout << "Incrementing in thread " << std::this_thread::get_id() << std::endl;
Counter++;
}
int main()
{
std::vector<std::thread> threads;
for (int i = 0; i < 2000; ++i) {
threads.push_back(std::thread(Inc));
}
// signal the threads to start
{
std::lock_guard<std::mutex> lk(m);
start = true;
}
cv.notify_all();
for (auto& thread : threads) {
thread.join();
}
// Now check whether value is right
std::cout << "Counter: " << Counter << std::endl;
}
结果看起来像这样(但后来有 2000 行)
Incrementing in thread 130960
Incrementing in thread 130948
Incrementing in thread 130944
Incrementing in thread 130932
Incrementing in thread 130928
Incrementing in thread 130916
Incrementing in thread 130912
Incrementing in thread 130900
Incrementing in thread 130896
Counter: 2000
如有任何帮助,我们将不胜感激
更新:将线程的 nr 减少到 4,但在 for 循环中递增一百万次(如@tkausl 所建议)线程 ID 的 cout
似乎是顺序的..
UPDATE2:事实证明必须解锁锁以防止每个线程进行独占访问 (lk.unlock()
)。 for 循环中的附加 yield
增加了竞争条件效应。
cv.wait(lk, [] {return start; });
仅 returns 获得了 lk
。所以它是排他性的。您可能想在
之后立即解锁 lk
void Inc() {
// Wait until test says start
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, [] {return start; });
lk.unlock();
Counter++;
}
并且您必须删除 std::cout
,因为它可能会引入同步。
我正在尝试对原子库进行单元测试(我知道原子库不适合进行单元测试,但我仍然想尝试一下)
为此,我想让 X 个并行线程递增一个计数器并计算结果值(应该是 X)。
代码如下。问题是它永远不会中断。 Counter
总是很好地以 2000 结束(见下文)。我还注意到 cout
也是作为一个整体打印的(而不是混合在一起,我记得在其他多线程 couts
中看到的)
我的问题是:为什么这不会中断?或者我怎样才能打破这种局面?
#include <iostream>
#include <thread>
#include <vector>
#include <mutex>
#include <condition_variable>
std::mutex m;
std::condition_variable cv;
bool start = false;
int Counter = 0;
void Inc() {
// Wait until test says start
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, [] {return start; });
std::cout << "Incrementing in thread " << std::this_thread::get_id() << std::endl;
Counter++;
}
int main()
{
std::vector<std::thread> threads;
for (int i = 0; i < 2000; ++i) {
threads.push_back(std::thread(Inc));
}
// signal the threads to start
{
std::lock_guard<std::mutex> lk(m);
start = true;
}
cv.notify_all();
for (auto& thread : threads) {
thread.join();
}
// Now check whether value is right
std::cout << "Counter: " << Counter << std::endl;
}
结果看起来像这样(但后来有 2000 行)
Incrementing in thread 130960
Incrementing in thread 130948
Incrementing in thread 130944
Incrementing in thread 130932
Incrementing in thread 130928
Incrementing in thread 130916
Incrementing in thread 130912
Incrementing in thread 130900
Incrementing in thread 130896
Counter: 2000
如有任何帮助,我们将不胜感激
更新:将线程的 nr 减少到 4,但在 for 循环中递增一百万次(如@tkausl 所建议)线程 ID 的 cout
似乎是顺序的..
UPDATE2:事实证明必须解锁锁以防止每个线程进行独占访问 (lk.unlock()
)。 for 循环中的附加 yield
增加了竞争条件效应。
cv.wait(lk, [] {return start; });
仅 returns 获得了 lk
。所以它是排他性的。您可能想在
lk
void Inc() {
// Wait until test says start
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, [] {return start; });
lk.unlock();
Counter++;
}
并且您必须删除 std::cout
,因为它可能会引入同步。