如何避免这两个相互关联的线程之间出现竞争状况

时间:2019-09-28 14:48:38

标签: c++ multithreading race-condition

由于我认为是比赛条件,我始终编写的小程序被阻止了。有人可以帮助我确定我的错误吗?

有一个功能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中的条件(等待直到完成多次迭代)是错误的。每当我在Anthony Williams的精彩著作(请参见2012年版4.1.1节)中的示例中使用条件变量时,一个函数就会运行,直到外部条件被否定,但在这里我有两个过程彼此依赖。有人可以指出我可以改善的地方吗?

0 个答案:

没有答案