Как я могу избежать состояния гонки между этими двумя взаимосвязанными потоками? - PullRequest
0 голосов
/ 28 сентября 2019

Небольшая программа, которую я написал последовательно, получает блокировку из-за того, что я считаю состоянием гонки.Может ли кто-нибудь помочь мне определить мою ошибку?

Существует одна функция, process_two, которая выполняет некоторые задачи, а затем использует другую функцию для обновления некоторой базовой структуры данных, прежде чем она может продолжиться. Примечание: эта функция запускается несколькими потоками одновременно Эта функция:

void process_two(int n_tasks) {
    while (total_iter < 100) {
        // do some work
        iter_since_update += n_tasks;
        total_iter += n_tasks;
        std::shared_lock<std::shared_mutex> lk(mutex);
        cv.wait(lk, [&] { return data_updated; });
        data_updated = false;
        lk.unlock();
    }
}

Функция выполняет некоторую работу и увеличивает количество выполненных задач.Затем он получает общую блокировку (если возможно) и ожидает условную переменную.После ожидания поток сбрасывает условие и разблокирует мьютекс.Функция, обновляющая базовую структуру данных:

void process_one(int threshold) {
    while (total_iter < 100) {
        if (iter_since_update >= threshold) {
            std::lock_guard<std::shared_mutex> lk(mutex);
            // updating
            data_updated = true;
            iter_since_update = 0;
            cv.notify_all();
        }
    }
}

Всякий раз, когда другая функция делает некоторое количество итераций, process_one получает блокировку и обновляет данные.Он также сбрасывает счетчик итераций и уведомляет другие потоки.Наконец, вся программа выглядит так:

#include <condition_variable>
#include <iostream>
#include <mutex>
#include <shared_mutex>
#include <thread>
#include <vector>

int iter_since_update(0);
bool data_updated(true);
std::shared_mutex mutex;
std::condition_variable_any cv;
int total_iter(0);

void process_two(int n_tasks) {
    while (total_iter < 100) {
        // do some work
        iter_since_update += n_tasks;
        total_iter += n_tasks;
        std::shared_lock<std::shared_mutex> lk(mutex);
        cv.wait(lk, [&] { return data_updated; });
        data_updated = false;
        lk.unlock();
    }
}

void process_one(int threshold) {
    while (total_iter < 100) {
        if (iter_since_update >= threshold) {
            std::lock_guard<std::shared_mutex> lk(mutex);
            // updating
            data_updated = true;
            iter_since_update = 0;
            cv.notify_all();
        }
    }
}

int main() {
    int total_tasks(10);
    int n_threads(1);
    int n_tasks = total_tasks / n_threads;
    std::thread update_thread([&]() { process_one(total_tasks);});
    std::vector<std::thread> threads;
    for (int i = 0; i < n_threads; i++)
        threads.push_back(std::thread([&]() { process_two(n_tasks); }));
    while (total_iter < 100) {
        ;
    }
    update_thread.join();
    for (int i = 0; i < n_threads; i++) threads[i].join();
}

Я установил общее количество задач и позволил каждому потоку, выполняющему process_two, выполнить часть этих задач.Всякий раз, когда я устанавливаю n_threads = 1, программа завершается почти всегда.Всякий раз, когда я устанавливал n_threads = 2, программа всегда терпела неудачу.

Я новичок в многопоточности в c ++ и буду очень признателен за любые предположения относительно того, что я делаю неправильно.Я подозреваю, что условие в process_one (ожидание, пока не будет выполнено несколько итераций) неверно.Всякий раз, когда я видел переменные условия, используемые в примерах в замечательной книге Энтони Уильямса (см. Раздел 4.1.1. В редакции 2012 года), одна функция работала до тех пор, пока внешнее условие не будет отменено, но здесь у меня оба процесса зависятдруг на друга.Может кто-нибудь любезно указать, что я могу улучшить?

...