Menguasai Multithreading C++: Pemrograman Konkuren Efisien
Multithreading adalah bentuk khusus dari multitasking, dan multitasking adalah fitur yang memungkinkan komputer Anda menjalankan dua atau lebih program secara bersamaan. Secara umum, ada dua jenis multitasking: berbasis proses dan berbasis thread.
Multitasking berbasis proses menangani eksekusi bersamaan program. Multitasking berbasis thread menangani eksekusi bersamaan bagian-bagian dari program yang sama.
Program multithreaded berisi dua atau lebih bagian yang dapat berjalan secara bersamaan. Setiap bagian dari program tersebut disebut thread, dan setiap thread mendefinisikan jalur eksekusi terpisah.
C++ tidak memiliki dukungan bawaan untuk aplikasi multithreaded. Sebaliknya, ia sepenuhnya bergantung pada sistem operasi untuk menyediakan fitur ini.
Tutorial ini mengasumsikan Anda bekerja pada sistem operasi Linux dan kami akan menulis program C++ multithread menggunakan POSIX. POSIX Threads, atau Pthreads, menyediakan API yang tersedia pada banyak sistem Unix-like POSIX seperti FreeBSD, NetBSD, GNU/Linux, Mac OS X, dan Solaris.
Membuat Thread
Rutinitas berikut digunakan untuk membuat thread POSIX −
#include <pthread.h> pthread_create (thread, attr, start_routine, arg)
Di sini, pthread_create membuat thread baru dan menjadikannya dapat dieksekusi. Rutinitas ini dapat dipanggil sebanyak kali dari mana saja dalam kode Anda. Berikut adalah deskripsi parameter −
| Sr.No | Parameter & Deskripsi |
| 1 | thread Pengidentifikasi unik dan tidak transparan untuk thread baru yang dikembalikan oleh subroutine. |
| 2 | attr Objek atribut tidak transparan yang dapat digunakan untuk mengatur atribut thread. Anda dapat menentukan objek atribut thread, atau NULL untuk nilai default. |
| 3 | start_routine Rutinitas C++ yang akan dieksekusi thread setelah dibuat. |
| 4 | arg Satu argumen yang dapat diteruskan ke start_routine. Harus diteruskan oleh referensi sebagai pointer cast tipe void. NULL dapat digunakan jika tidak ada argumen yang akan diteruskan. |
Jumlah maksimum thread yang dapat dibuat oleh proses bergantung pada implementasi. Setelah dibuat, thread adalah sejenis dan dapat membuat thread lain. Tidak ada hierarki atau dependensi yang tersirat antara thread.
Mengakhiri Thread
Ada rutinitas berikut yang digunakan untuk mengakhiri thread POSIX −
#include <pthread.h> pthread_exit (status)
Di sini pthread_exit digunakan untuk keluar secara eksplisit dari thread. Biasanya, rutinitas pthread_exit() dipanggil setelah thread telah menyelesaikan tugasnya dan tidak lagi perlu ada.
Jika main() selesai sebelum thread yang telah dibuat dan keluar dengan pthread_exit(), thread lain akan terus dieksekusi. Sebaliknya, mereka akan secara otomatis diakhiri ketika main() selesai.
Contoh
Contoh kode sederhana ini membuat 5 thread dengan rutinitas pthread_create(). Setiap thread mencetak pesan "Hello World!" dan kemudian mengakhiri dengan pemanggilan pthread_exit().
#include <iostream> #include <cstdlib> #include <pthread.h> using namespace std; #define NUM_THREADS 5 void *PrintHello(void *threadid) { long tid; tid = (long)threadid; cout << "Hello World! Thread ID, " << tid << endl; pthread_exit(NULL); } int main () { pthread_t threads[NUM_THREADS]; int rc; int i; for( i = 0; i < NUM_THREADS; i++ ) { cout << "main() : creating thread, " << i << endl; rc = pthread_create(&threads[i], NULL, PrintHello, (void *)i); if (rc) { cout << "Error:unable to create thread," << rc << endl; exit(-1); } } pthread_exit(NULL); } Kompilasi program berikut menggunakan perpustakaan -lpthread sebagai berikut −
$gcc test.cpp -lpthread
Sekarang, jalankan program Anda yang menghasilkan output berikut −
main() : creating thread, 0 main() : creating thread, 1 main() : creating thread, 2 main() : creating thread, 3 main() : creating thread, 4 Hello World! Thread ID, 0 Hello World! Thread ID, 1 Hello World! Thread ID, 2 Hello World! Thread ID, 3 Hello World! Thread ID, 4
Meneruskan Argumen ke Thread
Contoh ini menunjukkan cara meneruskan beberapa argumen melalui struktur. Anda dapat meneruskan tipe data apa pun dalam callback thread karena ia menunjuk ke void seperti dijelaskan dalam contoh berikut −
#include <iostream> #include <cstdlib> #include <pthread.h> using namespace std; #define NUM_THREADS 5 struct thread_data { int thread_id; char *message; }; void *PrintHello(void *threadarg) { struct thread_data *my_data; my_data = (struct thread_data *) threadarg; cout << "Thread ID : " << my_data->thread_id ; cout << " Message : " << my_data->message << endl; pthread_exit(NULL); } int main () { pthread_t threads[NUM_THREADS]; struct thread_data td[NUM_THREADS]; int rc; int i; for( i = 0; i < NUM_THREADS; i++ ) { cout <<"main() : creating thread, " << i << endl; td[i].thread_id = i; td[i].message = "This is message"; rc = pthread_create(&threads[i], NULL, PrintHello, (void *)&td[i]); if (rc) { cout << "Error:unable to create thread," << rc << endl; exit(-1); } } pthread_exit(NULL); } Ketika kode di atas dikompilasi dan dieksekusi, hasilnya adalah sebagai berikut −
main() : creating thread, 0 main() : creating thread, 1 main() : creating thread, 2 main() : creating thread, 3 main() : creating thread, 4 Thread ID : 3 Message : This is message Thread ID : 2 Message : This is message Thread ID : 0 Message : This is message Thread ID : 1 Message : This is message Thread ID : 4 Message : This is message
Gabungan dan Pemisahan Thread
Ada dua rutinitas berikut yang dapat kita gunakan untuk menggabungkan atau memisahkan thread −
pthread_join (threadid, status) pthread_detach (threadid)
Subrutin pthread_join() memblokir thread pemanggil sampai thread 'threadid' yang ditentukan diakhiri. Ketika thread dibuat, salah satu atributnya menentukan apakah thread dapat digabungkan atau dipisahkan. Hanya thread yang dibuat sebagai dapat digabungkan yang dapat digabungkan. Jika thread dibuat sebagai dipisahkan, ia tidak akan pernah dapat digabungkan.
Contoh ini menunjukkan cara menunggu penyelesaian thread menggunakan rutinitas gabungan Pthread.
#include <iostream> #include <cstdlib> #include <pthread.h> #include <unistd.h> using namespace std; #define NUM_THREADS 5 void *wait(void *t) { int i; long tid; tid = (long)t; sleep(1); cout << "Sleeping in thread " << endl; cout << "Thread with id : " << tid << " ...exiting " << endl; pthread_exit(NULL); } int main () { int rc; int i; pthread_t threads[NUM_THREADS]; pthread_attr_t attr; void *status; // Initialize and set thread joinable pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); for( i = 0; i < NUM_THREADS; i++ ) { cout << "main() : creating thread, " << i << endl; rc = pthread_create(&threads[i], &attr, wait, (void *)i ); if (rc) { cout << "Error:unable to create thread," << rc << endl; exit(-1); } } // free attribute and wait for the other threads pthread_attr_destroy(&attr); for( i = 0; i < NUM_THREADS; i++ ) { rc = pthread_join(threads[i], &status); if (rc) { cout << "Error:unable to join," << rc << endl; exit(-1); } cout << "Main: completed thread id :" << i ; cout << " exiting with status :" << status << endl; } cout << "Main: program exiting." << endl; pthread_exit(NULL); } Ketika kode di atas dikompilasi dan dieksekusi, hasilnya adalah sebagai berikut −
main() : creating thread, 0 main() : creating thread, 1 main() : creating thread, 2 main() : creating thread, 3 main() : creating thread, 4 Sleeping in thread Thread with id : 0 .... exiting Sleeping in thread Thread with id : 1 .... exiting Sleeping in thread Thread with id : 2 .... exiting Sleeping in thread Thread with id : 3 .... exiting Sleeping in thread Thread with id : 4 .... exiting Main: completed thread id :0 exiting with status :0 Main: completed thread id :1 exiting with status :0 Main: completed thread id :2 exiting with status :0 Main: completed thread id :3 exiting with status :0 Main: completed thread id :4 exiting with status :0 Main: program exiting.