Tentu saja, sebelum kita mulai berbicara tentang pemrograman thread POSIX, mari kita segarkan kembali beberapa konsep dasar dan pertimbangan desain dalam pemrograman memori bersama. Jadi, artikel ini cocok bagi mereka yang baru mengenal pemrograman paralel dengan thread POSIX atau terkadang disebut sebagai Pthreads.

Proses Vs Utas

Proses adalah program apa pun yang sedang dieksekusi yang memungkinkan Anda melakukan tindakan yang sesuai yang ditentukan dalam suatu program. Sedangkan utas adalah jalur eksekusi dalam suatu proses yang juga dianggap sebagai proses ringandan menggunakan sumber daya proses. Oleh karena itu, suatu proses dapat memiliki banyak thread, semuanya dijalankan pada waktu yang sama. Namun, perbedaan utamanya adalah thread dalam proses yang sama berjalan di ruang memori bersama, sedangkan proses berjalan di ruang memori terpisah. Oleh karena itu, dalam arsitektur multiprosesor memori bersama, thread dapat digunakan untuk mengimplementasikan paralelisme. Beberapa thread berbagi informasi seperti data, kode, sumber daya OS seperti file, dll. Mirip dengan proses, thread memiliki penghitung programnya sendiri, tumpukan, dan satu set register. Karena setiap thread memiliki sumber daya independen untuk eksekusi proses, beberapa proses dapat dieksekusi secara paralel dengan menambah jumlah thread.

Sekarang, Mari kita mulai dengan pemrograman POSIX…..

Utas POSIX atau Pthread

Thread POSIX atau lebih sering disebut Pthreads menentukan antarmuka pemrograman aplikasi (API) untuk pemrograman multithread berdasarkan UNIX. Tidak seperti C atau Java, Pthreads bukanlah bahasa pemrograman melainkan perpustakaan yang dapat dihubungkan dengan program C. Kecuali Pthreads, terdapat beberapa spesifikasi lain untuk pemrograman multithread seperti thread Java, thread Windows, thread Solaris, dll. Namun, dalam artikel ini mari kita lihat Pthreads dan setelah selesai, tidak akan sulit untuk mempelajari caranya program dengan API thread lain yang saya sebutkan sebelumnya.

Mengapa Pthread?

  • Ringan — Biasanya, biaya pembuatan dan pengelolaan suatu proses lebih tinggi dibandingkan biaya thread, dan oleh karena itu, thread dapat dibuat dengan overhead OS yang lebih sedikit. Selain itu, thread memerlukan sumber daya sistem yang lebih sedikit dibandingkan proses.
  • Komunikasi/Pertukaran Data yang Efisien — jika dibandingkan dengan menggunakan pustaka MPI (Message Passing Interface) untuk komunikasi on-node, penggunaan Pthreads dapat memberikan manfaat yang sangat besar dalam mencapai kinerja yang lebih baik. Pustaka MPI biasanya mengimplementasikan komunikasi tugas on-node melalui memori bersama, yang melibatkan setidaknya satu operasi penyalinan memori (proses ke proses). Sedangkan untuk Pthreads, tidak diperlukan penyalinan memori perantara karena thread berbagi ruang alamat yang sama dalam satu proses. Oleh karena itu, tidak ada transfer data dan bisa seefisien hanya dengan meneruskan sebuah pointer.

API Pthread

API Pthreads secara informal dapat dibagi menjadi empat kelompok besar.

  1. Manajemen Thread: menangani pembuatan, penghentian, dan penggabungan thread, dll.
  2. Mutex: berkaitan dengan sinkronisasi, yang disebut “mutex”, singkatan dari saling pengecualian. Fungsi mutex menyediakan untuk membuat, menghancurkan, mengunci, dan membuka kunci mutex.
  3. Variabel kondisi: mengatasi komunikasi di antara thread yang berbagi mutex. Ini menentukan fungsi untuk membuat, menghancurkan, menunggu, dan memberi sinyal berdasarkan nilai variabel yang ditentukan.
  4. Sinkronisasi: mengelola kunci dan hambatan baca/tulis.

Pada artikel ini, mari pelajari cara membuat dan mengakhiri thread menggunakan Pthreads API.

Eksekusi

Program Pthreads dikompilasi mirip dengan program C biasa dan sebagai tambahan, kita perlu menghubungkan perpustakaan Pthreads. Jika Anda menggunakan compiler GNU C, perintah compiler untuk program Pthreads adalah sebagai berikut.

gcc -g -Wall -o pth_name pth_name.c -lpthread

Manajemen Benang

Membuat dan Mengakhiri Thread

Awalnya, program main() Anda terdiri dari satu thread default dan tetap saja, semua thread lainnya harus dibuat secara eksplisit oleh pemrogram. Jadi, untuk membuat thread baru kita bisa menggunakan fungsi pthread_create di Pthreads API. Sintaks untuk pthread_create adalah,

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
    void *(*start_routine)(void*), void *arg);

Fungsi pthread_create memiliki empat argumen:

  • thread: Pengidentifikasi unik dan buram untuk thread baru yang dikembalikan oleh subrutin.
  • attr: Objek atribut buram yang dapat digunakan untuk menyetel atribut thread. Anda dapat menentukan objek atribut thread atau NULL untuk nilai default.
  • start_routine: rutinitas C yang akan dijalankan thread setelah dibuat.
  • arg: argumen tunggal yang dapat diteruskan ke start_routine. Itu harus diteruskan dengan referensi sebagai pointer bertipe void. NULL dapat digunakan jika tidak ada argumen yang ingin disampaikan.

Namun, ada beberapa cara untuk mengakhiri thread. Biasanya, sebuah thread berakhir setelah pekerjaannya selesai atau jika thread tersebut membuat panggilan ke subrutin pthreads_exit. Selain itu, sebuah thread dibatalkan oleh thread lain melalui rutinitas pthread_cancel. Kecuali hal-hal tersebut, seluruh proses dapat dihentikan dengan melakukan panggilan ke exec() atau exit(). Namun, masalah terjadi jika main() selesai sebelum thread muncul dan jika Anda tidak memanggil pthread_exit() secara eksplisit. Dalam skenario ini, ia akan menghentikan semua thread yang dibuatnya saat main() selesai dan tidak ada lagi. Tetapi jika Anda memanggil pthread_exit() secara eksplisit, maka main() akan diblokir dan tetap hidup atau mendukung thread yang dibuatnya hingga selesai.

Contoh: Pembuatan dan Penghentian Pthread

Sekarang mari selami contoh kode sederhana yang membuat 5 thread dengan subrutin pthread_create() dan diakhiri dengan panggilan ke rutinitas pthread_exit().

#include <pthread.h>
#include <stdio.h>
#define NUM_THREADS 5
void *PrintHello (void *threadid)
{
    long tid;
    tid = (long)threadid;
    printf("Hello World! It's me, thread #%ld!\n", tid);
    pthread_exit(NULL);
}
 int main (int argc, char *argv[])
 {
    pthread_t threads[NUM_THREADS];
    int rc;
    long t;
    for(t=0; t<NUM_THREADS; t++){
       printf("In main: creating thread %ld\n", t);
       rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);
       if (rc){
          printf("ERROR; return code from pthread_create() is %d\n", rc);
          exit(-1);
       }
    }
    /* Last thing that main() should do */
    pthread_exit(NULL);
 }

Sekarang, mari kita lihat lebih dekat kode sumber pada contoh. Seperti pada program C lainnya, program ini menyertakan beberapa file header yang familiar seperti stdio.h. Namun, di sini kita juga perlu menyertakan pthread.h, file header Pthread yang mendeklarasikan berbagai fungsi, konstanta, dan tipe Pthreads. Selanjutnya, Anda harus mendefinisikan variabel global untuk jumlah thread dan di sini ditetapkan ke 5. Kemudian kita menggunakan dua fungsi pthread_create() dan pthread_exit() yang telah kita bahas sebelumnya. Pertama, kami telah mengalokasikan penyimpanan untuk satu objek pthread_t untuk setiap thread. Argumen pertama pthread_create() adalah penunjuk ke objek pthread_t yang sesuai. Objek pthread_t ini adalah contoh objek buram dan oleh karena itu data aktual yang disimpannya bersifat spesifik sistem, dan anggota datanya tidak dapat diakses secara langsung oleh kode pengguna. Namun, standar Pthreads menjamin bahwa objek pthread_t menyimpan informasi yang cukup untuk mengidentifikasi thread yang terkait dengannya secara unik. Kita tidak akan menggunakan argumen kedua, jadi kita hanya meneruskan argumen NULL dalam pemanggilan fungsi kita. Argumen ketiga adalah fungsi yang akan dijalankan oleh thread, dan argumen terakhir adalah penunjuk ke argumen yang harus diteruskan ke fungsi start rutin. Jadi hasil akhirnya akan seperti di bawah ini.

In main: creating thread 0
In main: creating thread 1
Hello World! It's me, thread #0!
In main: creating thread 2
Hello World! It's me, thread #1!
Hello World! It's me, thread #2!
In main: creating thread 3
In main: creating thread 4
Hello World! It's me, thread #3!
Hello World! It's me, thread #4!

Kesimpulan

Pada artikel ini, saya hanya menjelaskan secara singkat satu bagian utama dalam Pthreads API yaitu Manajemen Thread. Di sana, saya menunjukkan cara membuat dan mengakhiri thread menggunakan contoh sederhana hello world. Namun, masih banyak lagi yang bisa dimainkan dengan Pthreads API dan sebagai permulaan saya sarankan bermain dengan contoh ini dan melihat bagaimana konkurensi mengambil tindakan.

Referensi

[1]”Pengantar Komputasi Paralel”, Computing.llnl.gov, 2020. [Online]. Tersedia: https://computing.llnl.gov/tutorials/parallel_comp/. [Diakses: 02-Sep-2020].