下面的代碼應該測驗具有不同執行緒數的 sin 和 cos 函式的運行時。我正在為一個運行時非常相關的專案寫這篇文章,并且多執行緒是否會足夠減少運行時是一項可行性研究。
這個想法是給它傳遞一個不同的 SAMPLE_SIZE 和 NUM_THREADS 并查看它如何影響運行時。
問題:輸出不是我所期望的。
- void 函式 cos_sin_multiplication 中的 ID 總是加一。所以我得到 (ID:1 ... ID:NUM_THREADS 1) 而不是 (ID:0 ... ID:NUM_THREADS)。
- 當我使用 2/3/4 執行緒運行代碼時,出現分段錯誤。
- 當我使用 7 個或更多執行緒運行時,幾個 ID 更改為 NUM_THREADS。
- cos_out[0] 的輸出始終為 0
這里是 NUM_THREADS = 8 和 SAMPLE_SIZE = 100'000 的示例輸出。
Initiate Thread: 0 with 12500 datapoints.
Initiate Thread: 1 with 12500 datapoints.
Initiate Thread: 2 with 12500 datapoints.
Initiate Thread: 3 with 12500 datapoints.
Initiate Thread: 4 with 12500 datapoints.
Initiate Thread: 5 with 12500 datapoints.
Initiate Thread: 6 with 12500 datapoints.
Initiate Thread: 7 with 12500 datapoints.
ID: 4: sin: 0.861292 cos: -1.72477
ID: 8: sin: -56.1798 cos: 55.4332
ID: 8: sin: -68.1969 cos: 51.9351
ID: 3: sin: 0.861292 cos: -1.72477
ID: 2: sin: 0.861292 cos: -1.72477
ID: 1: sin: 0.861292 cos: -1.72477
ID: 8: sin: -61.1793 cos: 58.8878
ID: 8: sin: -64.8086 cos: 59.5946
The execution took: 0.004465 seconds.
ID: 0: sin: 59.5946 cos: 0
ID: 1: sin: 0.861292 cos: -1.72477
ID: 2: sin: 0.861292 cos: -1.72477
ID: 3: sin: 0.861292 cos: -1.72477
ID: 4: sin: 0.861292 cos: -1.72477
ID: 5: sin: 0 cos: 0
ID: 6: sin: 0 cos: 0
ID: 7: sin: 0 cos: 0
誰能指出我正確的方向?
//Multithreaded Cosnius and Sinus Calculations Benchmark
// Calculate a sample of Cosinus and Sinus with different numbers of Threads
// to determine the runtime gain for different number of threads
#include <math.h>
#include <iostream>
#include <fstream>
#include <thread>
#include <mutex>
#include <chrono>
#include <vector>
#define NUM_THREADS 3
#define SAMPLE_SIZE 2000000
#define PI 3.1415
float diff_time;
std::ofstream calc_speed;
std::mutex out_guard;
void cos_sin_multiplication(int id, int sample, float theta, float& value, float& sin_out, float& cos_out){
for (int j = 0; j < sample; j ){
sin_out = sin(PI*theta);
cos_out = cos(PI*theta);
theta = 0.1;
}
out_guard.lock();
std::cout << "ID: " << id << ": sin: " << sin_out << " cos: " << cos_out << "\n";
out_guard.unlock();
}
int main(){
auto start_time = std::chrono::system_clock::now();
std::vector<std::thread> Threads;
int64_t sample_per_thread;
int mod_sample_per_thread = SAMPLE_SIZE%NUM_THREADS;
float value[SAMPLE_SIZE];
float theta = 0.0;
float cos_out[NUM_THREADS];
float sin_out[NUM_THREADS];
for(int i = 0; i < NUM_THREADS; i ){
cos_out[i] = 0.0;
sin_out[i] = 0.0;
}
for(int i = 0; i < NUM_THREADS; i ){
if (i < mod_sample_per_thread){
sample_per_thread = SAMPLE_SIZE/NUM_THREADS 1;
}
else{
sample_per_thread = SAMPLE_SIZE/NUM_THREADS;
}
out_guard.lock();
std::cout << "Initiate Thread: " << i <<" with "<< sample_per_thread << " datapoints." << "\n";
out_guard.unlock();
Threads.emplace_back([&](){cos_sin_multiplication(i, sample_per_thread, theta, value[0], sin_out[i], cos_out[i]);});
}
for(auto& t: Threads){
t.join();
}
auto end_time = std::chrono::system_clock::now();
std::chrono::duration<double> diff_time = end_time - start_time;
out_guard.lock();
std::cout << "The execution took: " << diff_time.count() << " seconds. \n";
out_guard.unlock();
for(int i = 0; i < NUM_THREADS; i ){
out_guard.lock();
std::cout << "ID: " << i << ": sin: " << sin_out[i] << " cos: " << cos_out[i] << "\n";
out_guard.unlock();
}
return 0;
}
解決方法: 將[&]替換為[&, i=i, sample_per_thread=sample_per_thread] st 只有需要通過參考傳遞的東西才通過參考傳遞。
uj5u.com熱心網友回復:
Threads.emplace_back([&](){cos_sin_multiplication(i, sample_per_thread, theta, value[0], sin_out[i], cos_out[i]);});
}
無論如何,C 不保證執行執行緒將實際開始執行此閉包的確切時間。您唯一可以依賴的是,這將在新std::thread物件構建后的某個時間點發生(作為 emplace 的一部分)。這遠非要使其正常作業必須發生的事情。一切正常的唯一情況是執行執行緒開始執行閉包,并在父執行執行緒迭代回圈之前for立即評估函式呼叫的所有引數。這樣的機會不是很好。
因此,除了其他所有錯誤之外,還有為其sample_per_thread計算的最后一個值。
完全有可能您的所有執行執行緒最終將最終執行此閉包,并在for回圈完成i并被銷毀后評估所有通過參考捕獲的引數,從而使所有行為都未定義。
即使某些執行執行緒設法早一點喚醒并聞到咖啡味,您仍然無法保證,這將是在構造物件sample_per_thread之前為它計算的內容。std::thread實際上,這幾乎可以保證至少一些執行執行緒將sample_per_thread在已經為下一個執行執行緒的表面消耗計算之后獲得通過參考捕獲的值。
換句話說,這里沒有任何東西可以正常作業,因為所有內容都是通過參考捕獲的。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/467456.html
上一篇:自定義執行緒池有什么缺點?
下一篇:為什么佇列不在主執行緒上更新?
