-
카테고리
-
세부 분야
프로그래밍 언어
-
해결 여부
해결됨
(과제스포)제가 과제를 똑바로 이해했는지 궁금합니다.
24.03.05 17:28 작성 24.03.05 17:31 수정 조회수 100
1
#include<chrono>
#include<iostream>
#include<mutex>
#include<random>
#include<thread>
#include<utility>
#include<vector>
#include<atomic>
#include<future>
#include<numeric>
#include<execution>
using namespace std;
mutex mtx;
void dotProductDQThread(const vector<int>& v0, const vector<int>& v1,
const unsigned i_start, const unsigned i_end, unsigned long long& sum)
{
int sum_tmp = 0; //local sum
for (unsigned i = i_start; i < i_end; ++i)
{
sum_tmp += v0[i] * v1[i];
}
sum += sum_tmp;
}
void dotProductProm(const vector<int>& v0, const vector<int>& v1,
const unsigned i_start, const unsigned i_end, promise<unsigned long long>&& sum)
{
int sum_tmp = 0; //local sum
for (unsigned i = i_start; i < i_end; ++i)
{
sum_tmp += v0[i] * v1[i];
}
sum.set_value(sum_tmp);
}
int main()
{
/*v0 = { 1,2,3 };
v1 = { 4,5,6 };
v0_dot = 1 * 4 + 2 * 5 + 3 * 6;*/
const long long n_data = 100'000'000;
const unsigned n_threads = 4;
//initialize vectors
std::vector<int> v0, v1;
v0.reserve(n_data);
v1.reserve(n_data);
random_device seed;
mt19937 engine(seed());
uniform_int_distribution<> uniformDist(1, 10);
//v0와 v1에 값 무작위로 넣어줌
for (long long i = 0; i < n_data; ++i)
{
v0.push_back(uniformDist(engine));
v1.push_back(uniformDist(engine));
//cout << v0[i] << "\t" << v1[i] << endl;
}
cout << "std::inner_product" << endl;
{
const auto sta = chrono::steady_clock::now();
const auto sum = std::inner_product(v0.begin(), v0.end(), v1.begin(), 0ull);//0ull = unsigned longlong 0
const chrono::duration<double> dur = chrono::steady_clock::now() - sta;
cout << dur.count() << endl;
cout << sum << endl;
cout << endl;
}
//TODO: use divde and conquer strategy for std::thread
cout << "TODO: use divde and conquer strategy for std::thread" << endl;
{
const auto sta = chrono::steady_clock::now();
unsigned long long sum = 0;
vector<thread> threads;
threads.resize(n_threads);
const unsigned n_per_thread = n_data / n_threads;
for (unsigned t = 0; t < n_threads; ++t)
threads[t] = std::thread(dotProductDQThread, std::ref(v0), std::ref(v1),
t * n_per_thread, (t + 1) * n_per_thread, std::ref(sum));
for (unsigned t = 0; t < n_threads; ++t)
threads[t].join();
const chrono::duration<double> dur = chrono::steady_clock::now() - sta;
cout << dur.count() << endl;
cout << sum << endl;
cout << endl;
}
//TODO: use promise
cout << "TODO: use promise" << endl;
{
const auto sta = chrono::steady_clock::now();
//std::promise<unsigned long long> sum;
auto sum = 0ull;
vector<thread> threads;
vector<future<unsigned long long>> futures;
vector<promise<unsigned long long>> proms;
threads.resize(n_threads);
futures.resize(n_threads);
proms.resize(n_threads);
const unsigned n_per_thread = n_data / n_threads;
for (unsigned t = 0; t < n_threads; ++t)
{
futures[t] = proms[t].get_future();
threads[t] = std::thread(dotProductProm, std::ref(v0), std::ref(v1),
t * n_per_thread, (t + 1) * n_per_thread, std::move(proms[t]));
}
for (unsigned t = 0; t < n_threads; ++t)
{
threads[t].join();
sum += futures[t].get();
}
const chrono::duration<double> dur = chrono::steady_clock::now() - sta;
cout << dur.count() << endl;
cout << sum << endl;
cout << endl;
}
}
결과는 제대로 나오지만, 제가 과제를 똑바로 이해했는지 궁금해서 여쭤봅니다.
과제1: use divde and conquer strategy for std::thread
쓰레드에 sum에 local sum값을 넣어 race condition 해결과제2: prom 사용해보기
sum 변수 선언 및 thread, promise, future 모두 쓰레드 크기 만큼의 vector로 만들어줬습니다.
병렬 처리 후 future값을 sum에 더해줬습니다.
※추가 궁금증
promise 과제 중, std::ref와 std::move 둘 다 해보았습니다. 두 경우 모두 정상 작동하였는데, 어떤 방법을 가장 추천하시나요?
답변을 작성해보세요.
1
Soobak
2024.03.06
안녕하세요, 질문&답변 도우미 Soobak 입니다.
과제 1)
: 여러 스레드를 통한 병렬 처리 작업에 대해서는 잘 작성하셨지만, sum += sum_tmp
에 대해서 sum
에 대한 race condition
을 방지하기 위한 mutex
의 사용을 누락하신 것 같습니다.mutex mtx;
의 정의는 되어있지만, mtx
를 사용하신 곳이 없습니다.
이 부분에 대해서 점검하시어, 각 스레드가 sum
에 값을 추가하기 전에 mutex
로 접근을 제어하여 보호하는 방법을 생각해보시면 좋을 것 같습니다.
과제 2)
: promise
와 future
에 대해서 잘 이해하시고, race condition
을 방지하며 올바르게 합계를 계산하도록 잘 작성하신 것 같습니다. 👍
추가적으로, std::ref
는 참조자(wrapper)를 생성하여 함수나 스레드 생성자로 '객체를 참조로 전달할 때' 사용합니다. 따라서, 객체를 복사하지 않고 참조를 전달하고자 할 때 유용합니다.
std::move
는 '객체의 소유권을 이동' 시키는 데에 사용됩니다. 주로 객체의 복사를 피하고 리소스를 효율적으로 이전하고자 할 때 사용됩니다.
위 두 개념을 잘 비교하시어 이해해보시면 학습에 보다 더 도움이 되실 것 같습니다.
이 때, promise
객체의 경우, 복사는 할 수 없으며 오직 이동만 가능하기 때문에, std::move
를 사용하여 promise
객체를 스레드 함수로 전달하는 것이 적절합니다.
전반적으로 잘 작성하셨으며, 과제 1 에서 race condition
을 해결하기 위한 mutex
사용이 누락된 부분만 보완하시면 좋을 것 같습니다.
👍
답변 1