Multithreading C++: Panduan untuk Pemula

Halo para jagoan编码 masa depan! Saya sangat senang menjadi pemandu Anda dalam perjalanan yang menarik ini ke dunia multithreading C++. Sebagai seseorang yang telah mengajar pemrograman selama tahun-tahun, saya bisa menjamin bahwa meskipun topik ini mungkin terlihat menakutkan saat pertama kali, namun itu benar-benar sangat menarik sekali Anda mengerti cara kerjanya. Jadi, mari kita ganti tangan dan melompatlah!

C++ Multithreading

Apa itu Multithreading?

Sebelum kita melompat ke hal-hal yang kacau, mari kita mulai dari dasar-dasar. Bayangkan Anda berada di dapur, mencoba untuk mempersiapkan makanan yang kompleks. Anda bisa melakukan semua langkah satu per satu – mengiris sayuran, lalu merebus pasta, lalu membuat saus. Tetapi apakah tidak lebih efisien jika Anda bisa melakukan semua tugas ini secara bersamaan? Itulah yang sebenarnya melakukan multithreading untuk program kami!

Multithreading memungkinkan suatu program untuk melakukan banyak tugas secara bersamaan. Setiap tugas ini dipanggil sebuah "thread". Itu seperti memiliki banyak juru masak di dapur, masing-masing bertanggung jawab atas bagian yang berbeda dari makanan.

Sekarang, mari kita jelajahi bagaimana kita dapat mengeksploitasi kekuatan ini di C++!

Membuat Threads

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

Mari lihat contoh sederhana:

#include <iostream>
#include <thread>

void merebusPasta() {
std::cout << "Merebus pasta..." << std::endl;
}

int main() {
std::thread juruMasakSatu(merebusPasta);
juruMasakSatu.join();
return 0;
}

Dalam contoh ini:

  1. Kita menyertakan pustaka yang diperlukan: <iostream> untuk input/output dan <thread> untuk multithreading.
  2. Kita mendefinisikan fungsi merebusPasta() yang akan dieksekusi oleh thread.
  3. Di main(), kita membuat sebuah thread yang dipanggil juruMasakSatu dan memberitahu itu untuk menjalankan fungsi merebusPasta().
  4. Kita menggunakan join() untuk menunggu thread selesai melakukan tugas sebelum program berakhir.

Ketika Anda menjalankan program ini, Anda akan melihat "Merebus pasta..." dicetak ke konsol. Selamat! Anda baru saja membuat thread pertama Anda!

Menghentikan Threads

Apa yang terjadi jika juru masak kita terlalu lama untuk merebus pasta? Di dunia pemrograman, kita mungkin perlu menghentikan sebuah thread sebelum itu menyelesaikan tugasnya. Namun, penting untuk dicatat bahwa mengehentikan thread secara paksa dapat menyebabkan kebocoran sumber daya dan masalah lainnya. Umumnya, lebih baik untuk mendesain thread Anda untuk selesai secara alami atau merespon sinyal penghentian.

Berikut adalah contoh tentang bagaimana kita dapat mengatur sebuah thread untuk merespon sinyal penghentian:

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

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

void merebusPasta() {
while (!stop_thread) {
std::cout << "Masih merebus pasta..." << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
std::cout << "Merebus pasta dihentikan!" << std::endl;
}

int main() {
std::thread juruMasakSatu(merebusPasta);

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

juruMasakSatu.join();
return 0;
}

Dalam contoh ini:

  1. Kita menggunakan variabel atomic<bool> stop_thread untuk berkomunikasi secara aman antar thread.
  2. Fungsi merebusPasta() sekarang memeriksa variabel ini di atas loop.
  3. Di main(), kita membiarkan thread berjalan selama 5 detik, lalu mengatur stop_thread menjadi true.
  4. Thread merespon dengan menyelesaikan loop dan mengakhiri secara alami.

Mengirim Argumen ke Threads

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

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

void memasakMakanan(std::string makanan, int waktu) {
std::cout << "Memasak " << makanan << " selama " << waktu << " menit." << std::endl;
}

int main() {
std::thread juruMasakSatu(memasakMakanan, "Spaghetti", 10);
std::thread juruMasakDua(memasakMakanan, "Pizza", 15);

juruMasakSatu.join();
juruMasakDua.join();

return 0;
}

Dalam contoh ini:

  1. Fungsi memasakMakanan() sekarang mengambil dua parameter: nama makanan dan waktu memasak.
  2. Kita membuat dua thread, masing-masing memasak makanan yang berbeda selama waktu yang berbeda.
  3. Kita mengirim argumen ini langsung saat membuat thread.

Ini menunjukkan betapa fleksibel thread bisa być - kita dapat memiliki banyak thread melakukan tugas yang mirip dengan parameter yang berbeda!

Menggabungkan dan Melepaskan Threads

Akhirnya, mari kita berbicara tentang dua konsep penting: menggabungkan dan melepaskan thread.

Menggabungkan Threads

Kita sudah melihat join() di contoh sebelumnya. Ketika kita memanggil join() pada sebuah thread, kita memberitahu program utama untuk menunggu thread tersebut selesai sebelum melanjutkan. Itu seperti menunggu seorang juru masak menyelesaikan penghasilan masakan sebelum menyajikan makan.

Melepaskan Threads

Terkadang, kita mungkin ingin membiarkan thread berjalan secara independen tanpa menunggu itu selesai. Itulah saat detach() masuk ke tugas. Thread yang dilepaskan terus berjalan di latar belakang, bahkan setelah program utama berakhir.

Berikut adalah contoh yang menggambarkan kedua:

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

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

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

int main() {
std::thread juruMasakLama(memasakLama, "Stew");
std::thread juruMasakCepat(memasakCepat, "Salad");

juruMasakLama.detach();  // Biarkan juru masak lama bekerja di latar belakang
juruMasakCepat.join();   // Tunggu juru masak cepat selesai

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

Dalam contoh ini:

  1. Kita memiliki dua juru masak: satu memasak stew secara lama, dan satu lagi cepat membuat salad.
  2. Kita melepaskan thread juru masak lama, memungkinkannya untuk terus bekerja di latar belakang.
  3. Kita menggabungkan thread juru masak cepat, menunggu salad siap.
  4. Program utama berakhir, potensielle sebelum stew siap.
Metode Deskripsi Kasus Penggunaan
join() Menunggu thread selesai Ketika Anda perlu hasil thread sebelum melanjutkan
detach() Memungkinkan thread berjalan secara independen Untuk tugas latar belakang yang dapat berjalan secara otonom

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

Selamat coding, dan semoga thread Anda selalu berjalan mulus!

Credits: Image by storyset