gpt4 book ai didi

c++ - 使用 promise 数组的段错误

转载 作者:搜寻专家 更新时间:2023-10-31 00:55:55 27 4
gpt4 key购买 nike

我编写了多线程程序,使用 promises 和 futures 来检查给定数字是否为质数。这个程序的正确性或效率不是重点,而是每次执行时发生的段错误的事实——我在更复杂的程序中遇到过类似的问题,所以我写了这个简单的程序来理解它,但错误仍然存​​在这里。也许我不了解并发性或 promise / future ,但我认为这里的一切都以适当的方式完成......有人可以解释为什么它不起作用吗?这将非常有帮助:)

代码如下:

#include <future>
#include <thread>
#include <iostream>
#include <initializer_list>
#include <vector>
#include <cassert>


namespace {
const int THREADS_NUMBER = 8;

void f(int n, std::vector<int>& divisiors, std::promise<bool>& isPossiblePrime) {
bool isPrimeCandidate = true;
for (auto i : divisiors)
if (n % i == 0) {
isPrimeCandidate = false;
break;
}
isPossiblePrime.set_value(isPrimeCandidate);
}


}

int main() {
int n;
std::cin >> n;
assert(n > 2);
std::promise<bool> promises[THREADS_NUMBER];
std::future<bool> futures[THREADS_NUMBER];
for (int i = 0; i < n; i++)
futures[i] = promises[i].get_future();
std::thread threads[THREADS_NUMBER];

std::vector<int> divisiors[THREADS_NUMBER];
for (int i = 2; i < n; i++)
divisiors[i % THREADS_NUMBER].push_back(i);

for (int i = 0; i < THREADS_NUMBER; i++)
threads[i] = std::thread{ [&]() { f(n, divisiors[i], promises[i]); }};

bool isPrime = true;
for(auto & f : futures) {
bool out = f.get();
isPrime = out && isPrime;
}

for (auto& t : threads)
t.join();

if(isPrime) std::cout << "PRIME" << std::endl;
else std::cout << "NOT PRIME" << std::endl;

}

我在 Linux 上用 g++ -std=c++11 -Wall -lpthread 编译。

最佳答案

问题发生在:

for (int i = 0; i < THREADS_NUMBER; i++) 
threads[i] = std::thread{ [&]() { f(n, divisiors[i], promises[i]); }};

[&] 通过引用捕获所有变量。这包括 promisesi。但是,lambda 中的代码尚未执行。直到操作系统设置好线程等,它才会运行。当线程开始执行时,主线程的 for 循环已经结束,变量 i 结束了它的生命周期。

但随后线程执行 promises[i],其中两者都是引用捕获。它会查找 promisesi 的引用以执行此操作。 promises 很好,但是 i 指的是一个不再存在的变量。段错误可能是由于 i 由于此查找而具有垃圾值,然后越界访问。

即使将 int i; 提升到循环之外也不能解决问题;然后 lambda 中的引用确实找到了 i,但它在完成 THREADS_NUMBER 循环后具有最终值,这超出了 promises数组。

要解决这个问题,按值捕获i:

threads[i] = std::thread{ [&,i]() { f(n, divisiors[i], promises[i]); }};

然后每个 lambda 使用创建 lambda 时 i 的值。


注意:我认为 std::thread 可以将临时 lambda 作为构造函数参数,但我对此也不确定。该标准似乎确实说线程构造函数复制了提供的仿函数。但是我搜索的所有 cppreference 示例都首先创建了一个命名的 lambda,然后将该名称作为构造函数参数提供给 std::thread

关于c++ - 使用 promise 数组的段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40922845/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com