Panduan Multithreading C++: Untuk Pemula

Hai di sana, superstars pengoding masa depan! Saya sangat gembira untuk menjadi pemandu anda dalam perjalanan yang menarik ini ke dunia multithreading C++. Sebagai seseorang yang telah mengajar pemrograman selama bertahun-tahun, saya dapat memberikan jaminan kepada anda bahwa walaupun topik ini mungkin terasa menakutkan pada awalnya, ia sebenarnya sangat menarik sekali anda mengerti cara kerjanya. Jadi, mari kita melepas lengan dan koyak masuk!

C++ Multithreading

Apa itu Multithreading?

Sebelum kita melompat ke detilnya, mari kita mulakan dengan dasar-dasar. Bayangkan anda berada di dapur, mencuba untuk mempersiapkan makanan yang kompleks. Anda boleh melakukan setiap langkah secara berurutan – untuk memotong sayur, kemudian untuk kukus pasta, kemudian untuk mempersiapkan sos. Tetapi apakah tidak lebih efisien jika anda dapat melakukan semua tugas ini secara serentak? Itulah yang sebenarnya multithreading lakukan untuk program kita!

Multithreading membolehkan program untuk melakukan beberapa tugas secara bersamaan. Setiap tugas ini dipanggil "thread". Ia seperti memiliki beberapa juru masak di dapur, masing-masing bertanggungjawab atas beberapa bahagian makanan.

Sekarang, mari kita eksplor bagaimana kita boleh menggunakkan kekuatan ini di C++!

Membuat Threads

Membuat sebuah thread di C++ adalah seperti mengambil juru masak baru untuk dapur kita. Kita perlu memberitahu juru masak (thread) ini tugas apa yang hendak diperakukan. Di C++, kita melakukan ini menggunakan kelas std::thread dari pustaka <thread>.

Mari lihat contoh yang simple:

#include <iostream>
#include <thread>

void cookPasta() {
std::cout << "Memasak pasta..." << std::endl;
}

int main() {
std::thread chefOne(cookPasta);
chefOne.join();
return 0;
}

Dalam contoh ini:

  1. Kita sertakan pustaka yang diperlukan: <iostream> untuk input/output dan <thread> untuk multithreading.
  2. Kita definisikan fungsi cookPasta() yang thread akan menjalankan.
  3. Di main(), kita membuat thread yang dipanggil chefOne dan memberitahu untuk menjalankan fungsi cookPasta().
  4. Kita gunakan join() untuk menunggu thread selesai tugasnya sebelum program berakhir.

Apabila anda menjalankan program ini, anda akan lihat "Memasak pasta..." dicetak di atas konsol. Selamat! Anda baru saja membuat thread pertama anda!

Menghentikan Threads

Apa jika juru masak kita terlalu lama untuk memasak pasta? Di dunia pemrograman, kita mungkin perlu menghentikan sebuah thread sebelum ia menyelesaikan tugasnya. Walau bagaimanapun, penting untuk diperhatikan bahwa penghentian paksa thread dapat menyebabkan kebocoran sumber daya dan masalah lain. Umumnya, lebih baik untuk merancang thread anda untuk selesai secara alami atau merespon sinyal penghentian.

Berikut adalah contoh bagaimana kita mungkin mengatur thread untuk merespon sinyal penghentian:

#include <iostream>
#include <thread>
#include <atomic>

std::atomic<bool> stop_thread(false);

void cookPasta() {
while (!stop_thread) {
std::cout << "Masih memasak pasta..." << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
std::cout << "Peng.masakan pasta dihentikan!" << std::endl;
}

int main() {
std::thread chefOne(cookPasta);

std::this_thread::sleep_for(std::chrono::seconds(5));
stop_thread = true;

chefOne.join();
return 0;
}

Dalam contoh ini:

  1. Kita gunakan variabel atomic<bool> stop_thread untuk berkomunikasi secara aman antara threads.
  2. Fungsi cookPasta() kita sekarang memeriksa variabel ini di atas loop.
  3. Di main(), kita membiarkan thread berjalan selama 5 saat, kemudian menetapkan stop_thread menjadi true.
  4. Thread merespon dengan menyelesaikan loopnya dan berakhir secara alami.

Mengirimkan Argumen ke Threads

Apa jika kita ingin memberikan instruksi lebih spesifik kepada juru masak kita? Di C++, kita boleh mengirimkan argumen ke thread kita seperti kita mengirimkan argumen ke fungsi. Mari kita lihat bagaimana:

#include <iostream>
#include <thread>
#include <string>

void cookDish(std::string dish, int time) {
std::cout << "Memasak " << dish << " selama " << time << " minit." << std::endl;
}

int main() {
std::thread chefOne(cookDish, "Spaghetti", 10);
std::thread chefTwo(cookDish, "Pizza", 15);

chefOne.join();
chefTwo.join();

return 0;
}

Dalam contoh ini:

  1. Fungsi cookDish() kita sekarang menerima dua parameter: nama makanan dan waktu memasak.
  2. Kita membuat dua thread, masing-masing memasak makanan yang berbeza untuk jumlah waktu yang berbeza.
  3. Kita kirimkan argumen ini secara langsung ketika membuat threads.

Ini menunjukkan betapa fleksibel thread bisa jadi - kita boleh memiliki beberapa thread melakukan tugas yang serupa dengan parameter yang berbeza!

Menggabungkan dan Melepaskan Threads

Akhirnya, mari kita berbicara tentang dua konsep penting: penggabungan dan pelepasan threads.

Menggabungkan Threads

Kita sudah pernah lihat join() di contoh sebelumnya. Apabila kita memanggil join() pada sebuah thread, kita memberitahu program utama kita untuk menunggu thread itu selesai sebelum melanjutkan. Ia seperti menunggu juru masak untuk menyelesaikan penyajian makanan sebelum menyajikan makanan.

Melepaskan Threads

Kadang-kadang, kita mungkin ingin membiarkan thread berjalan secara independen tanpa menunggu untuk ia selesai. Itulah saat detach() datang ke tempatnya. Thread yang dilepaskan terus berjalan di latar belakang, bahkan setelah program utama berakhir.

Berikut adalah contoh yang mengilustrasikan kedua-duanya:

#include <iostream>
#include <thread>
#include <chrono>

void slowCook(std::string dish) {
std::this_thread::sleep_for(std::chrono::seconds(3));
std::cout << dish << " sudah siap!" << std::endl;
}

void quickCook(std::string dish) {
std::cout << dish << " sudah siap!" << std::endl;
}

int main() {
std::thread slowChef(slowCook, "Stew");
std::thread quickChef(quickCook, "Salad");

slowChef.detach();  // Biarkan juru masak lambat bekerja di latar belakang
quickChef.join();   // Tunggu juru masak cepat selesai

std::cout << "Program utama berakhir. Juru masak lambat mungkin masih bekerja!" << std::endl;
return 0;
}

Dalam contoh ini:

  1. Kita memiliki dua juru masak: satu yang memasak stew lambat, dan satu yang cepat menghidang salad.
  2. Kita melepaskan thread juru masak lambat, membolehkan ia untuk terus bekerja di latar belakang.
  3. Kita menggabungkan thread juru masak cepat, menunggu salad untuk siap.
  4. Program utama berakhir, potensi sebelum stew siap.
Method Description Use Case
join() Menunggu thread selesai Apabila anda perlu hasil thread sebelum melanjutkan
detach() Membolehkan thread berjalan secara independen Untuk tugas latar belakang yang boleh berjalan secara autonomi

Dan itu adalah dia, folks! Anda baru saja mengambil langkah pertama anda ke dunia multithreading C++. Ingat, seperti belajar untuk memasak, menguasai multithreading memerlukan praktek. Jangan takut untuk bereksperimen dengan konsep ini, dan segera anda akan menghidangkan program kompleks dan efisien seperti juru masak master di dapur kode!

Happy coding, dan semoga threads anda selalu berjalan mulus!

Credits: Image by storyset