Мне нужно преобразовать эту программу, которая выполняет итерацию, разделить шаги итерации на 4 потока. Если итерация равна n, тогда я выполняю ее, используя 4 потока. Работа программы занимает в среднем 4,7 с. Сумма доступна для всех 4 потоков, и при обновлении возникает проблема. Я получаю 1.5 в качестве ответа вместо 3.1457 для значения pi. Также многопоточность не уменьшает время. пожалуйста, помогите мне
#include "stdafx.h"#include <iostream>
#include <chrono>
#include <thread>
#include <functional>
#include <mutex>
//std::mutex m;
long num_rects = 100000000;
struct params
{
int start;
int end;
double mid;
double height;
double width;
params(int st,int en)
{
start = st;
end = en;
width = 1.0 / (double)num_rects;
}
};
double sum = 0.0;void sub1(params param){
for (int i = param.start; i < param.end; i++)
{
param.mid = (i + 0.5)*param.width;
param.height = 4.0 / (1.0 + param.mid*param.mid);
//m.lock();
sum += param.height;
//m.unlock();
}
}int _tmain(int argc, _TCHAR* argv[])
{
int i;
double mid, height, width;
double area;
auto begin = std::chrono::high_resolution_clock::now();
params par(0, num_rects / 4);
std::thread t(sub1, par);
params par1(num_rects / 4, num_rects / 2);
std::thread t1(sub1, par1);
params par2(num_rects / 2, (num_rects *3)/ 4);
std::thread t2(sub1, par2);
params par3((num_rects * 3) / 4, num_rects );
std::thread t3(sub1, par3);
t.join();
t1.join();
t2.join();
t3.join();
/*
sub1(par);
sub1(par1);
sub1(par2);
sub1(par3);
*/width = 1.0 / (double)num_rects;
area = sum*width;
std::cout << area << std::endl;
auto end = std::chrono::high_resolution_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count() << "ms" << std::endl;
std::cin.get();
return 0;
}
Вы страдаете от состояния гонки, чтобы записать сумму, поэтому 2 потока могут перезаписать сумму различными значениями, а затем обновленное значение будет перезаписано.
Это изменение должно работать.
double sub1(params param){
double sum = 0.0; // thread local
for (int i = param.start; i < param.end; i++)
{
param.mid = (i + 0.5)*param.width;
param.height = 4.0 / (1.0 + param.mid*param.mid);
sum += param.height;
}
return sum;
}
#include <future>
int SubMain() {
int i;
double mid, height, width;
double area;
auto begin = std::chrono::high_resolution_clock::now();
params par(0, num_rects / 4);
std::future<double> fut1 = std::async (sub1, par);
params par1(num_rects / 4, num_rects / 2);
std::future<double> fut2 = std::async (sub1, par1);
params par2(num_rects / 2, (num_rects *3)/ 4);
std::future<double> fut3 = std::async (sub1, par2);
params par3((num_rects * 3) / 4, num_rects );
std::future<double> fut4 = std::async (sub1, par3);
sum = fut1.get() + fut2.get() + fut3.get() + fut4.get();
width = 1.0 / (double)num_rects;
area = sum*width;
std::cout << area << std::endl;
auto end = std::chrono::high_resolution_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count() << "ms" << std::endl;
std::cin.get();
return 0;
}
внес некоторые изменения в код Сурта, это финальная оптимизированная версия
double sub1(params param){
double sum = 0.0; // thread local
for (int i = param.start; i < param.end; i++)
{
param.mid = (i + 0.5)*param.width;
param.height = 4.0 / (1.0 + param.mid*param.mid);
sum += param.height;
}
return sum;
}
#include <future>
#include <vector>
int SubMain() {
int i;
double mid, height, width;
double area;
auto begin = std::chrono::high_resolution_clock::now();
std::vector<std::future<double>> futures;
double k = 0;
for (int j = 0; j < 4; j++)
{
params par(num_rects *k, num_rects *(k + 0.25));
k += 0.25;
futures.push_back(std::async(sub1, par));
}
for (std::vector<std::future<double>> ::iterator it = futures.begin(); it != futures.end(); it++)
{
sum += it->get();
}
/* params par(0, num_rects / 4);
std::future<double> fut1 = std::async(sub1, par);
params par1(num_rects / 4, num_rects / 2);
std::future<double> fut2 = std::async(sub1, par1);
params par2(num_rects / 2, (num_rects * 3) / 4);
std::future<double> fut3 = std::async(sub1, par2);
params par3((num_rects * 3) / 4, num_rects);
std::future<double> fut4 = std::async(sub1, par3);
sum = fut1.get() + fut2.get() + fut3.get() + fut4.get();*/width = 1.0 / (double)num_rects;
area = sum*width;
std::cout << area << std::endl;
auto end = std::chrono::high_resolution_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count() << "ms" << std::endl;
std::cin.get();
return 0;
}