Принудительное одновременное изменение переменной (C ++) - PullRequest
0 голосов
/ 21 ноября 2018

Я пытаюсь выполнить модульное тестирование атомарной библиотеки (я знаю, что атомарная библиотека не подходит для модульного тестирования, но я все еще хочу попробовать)

Для этого я хочупусть параллельные потоки 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

Любая помощь будет оценена

ОБНОВЛЕНИЕ:Сокращение числа потоков до 4, но увеличение в миллион раз в цикле for (как это предлагает @tkausl) cout идентификатора потока выглядит последовательным.

UPDATE2: Оказывается, блокировкадолжен был быть разблокирован для предотвращения монопольного доступа для каждого потока (lk.unlock()).Дополнительные yield в цикле for увеличивали эффект состояния гонки.

1 Ответ

0 голосов
/ 21 ноября 2018

cv.wait(lk, [] {return start; }); возвращается только с полученным 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, потому что это потенциально может привести к синхронизации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...