Saya mencoba memahami Multi-threading di c ++, tapi saya terjebak dalam masalah ini: jika saya meluncurkan utas dalam untuk loop mereka mencetak nilai yang salah. Ini kodenya:
#include <iostream>
#include <list>
#include <thread>
void print_id(int id){
printf("Hello from thread %d\n", id);
}
int main() {
int n=5;
std::list<std::thread> threads={};
for(int i=0; i<n; i++ ){
threads.emplace_back(std::thread([&](){ print_id(i); }));
}
for(auto& t: threads){
t.join();
}
return 0;
}
Saya berharap bisa mencetak nilai 0,1,2,3,4 tetapi saya sering mendapatkan nilai yang sama dua kali. Ini hasilnya:
Hello from thread 2
Hello from thread 3
Hello from thread 3
Hello from thread 4
Hello from thread 5
Apa yang saya lewatkan?
c++
multithreading
Ermando
sumber
sumber
i
nilai ke lambda[i]
,.emplace_back
aneh:emplace_back
mengambil daftar argumen dan meneruskannya ke konstruktorstd::thread
. Anda telah melewati instance (rvalue) daristd::thread
, maka akan membangun utas, lalu memindahkan utas itu ke vektor. Operasi itu lebih baik diungkapkan dengan metode yang lebih umumpush_back
. Akan lebih masuk akal baik menulisthreads.emplace_back([i](){ print_id(i); });
(membangun di tempat) atauthreads.push_back(std::thread([i](){ print_id(i); }));
(membangun + bergerak) yang agak lebih idiomatis.Jawaban:
The
[&]
sintaks yang menyebabkani
ditangkap oleh referensi . Jadi, cukup sering karena itui
akan lebih maju ketika utas berjalan dari yang Anda harapkan. Lebih serius lagi, perilaku kode Anda tidak terdefinisi jikai
keluar dari cakupan sebelum utas berjalan.Menangkap
i
berdasarkan nilai - yaitustd::thread([i](){ print_id(i); })
memperbaiki.sumber
std::thread([=](){ print_id(i); })
i
dengan utas utama dan pembacaan utas lainnya.Dua masalah:
Anda tidak memiliki kontrol atas ketika utas berjalan, yang berarti nilai variabel
i
di lambda mungkin tidak seperti yang Anda harapkan.Variabel
i
lokal untuk loop dan loop saja. Jika loop selesai sebelum satu atau lebih utas berjalan, utas tersebut akan memiliki referensi yang tidak valid ke variabel yang masa pakainya telah berakhir.Anda dapat menyelesaikan kedua masalah ini dengan sangat sederhana dengan menangkap variabel
i
berdasarkan nilai alih-alih dengan referensi. Itu berarti setiap utas akan memiliki salinan nilainya, dan salinan itu akan dibuat secara unik untuk setiap utas.sumber
Hal lain:
Jangan menunggu sampai selalu urutan yang terurut: 0, 1, 2, 3, ... karena mode eksekusi multithreading memiliki kekhususan: ketidakpastian .
Indeterminisme berarti bahwa pelaksanaan program yang sama, di bawah kondisi yang sama, memberikan hasil yang berbeda.
Ini disebabkan oleh kenyataan bahwa jadwal OS threads berbeda dari satu eksekusi ke yang lain tergantung pada beberapa parameter: beban CPU, prioritas proses lain, kemungkinan gangguan sistem, ...
Contoh Anda hanya berisi 5 utas, jadi sederhana, coba tambah jumlah utas, dan misalnya tidur di fungsi pemrosesan, Anda akan melihat bahwa hasilnya dapat berbeda dari satu eksekusi ke yang lain.
sumber