Mengenal pemrograman multithread dengan Delphi 7 Oleh: Catur Budi Santoso
Aplikasi dengan teknik multi-threading adalah aplikasi yang banyak kita temui di komputer kita sekarang ini, entah kita sadari atau tidak. Di aplikasi multithreading terdapat thread-thread yang berjalan paralel dalam processor.
Artikel ini ditujukan bagi pengguna delphi yang telah mengenal delphi tapi belum terlalu mendalam dan belum mempunyai pengalaman dengan pemrograman muli-tthreading. Artikel ini juga saya publish di wordpress saya.
Sekilas tentang Multi-Threading
Aplikasi dengan teknik multi-threading adalah aplikasi yang banyak kita temui di komputer kita sekarang ini, entah kita sadari atau tidak. Di aplikasi multithreading terdapat beberapa thread yang berjalan paralel dalam processor. Lawan kata dari aplikasi multi-threading adalah aplikasi single threading yang menggunakan satu thread saja sehingga semua intruksi berjalan secara serial atau berurutan. Di delphi ketika kita membuat aplikasi otomatis terbuat aplikasi single-threading.
Pemrograman multithreading sederhananya adalah pemrograman dengan membagi kumpulan-kumpulan kode kita kedalam thread-thread yang akan dijalankan secara paralel setelah aplikasinya dicompile. Masing-masing thread tersebut masih dapat saling berkomunikasi satu sama lainnya dengan sharing sumber daya memori variabel atau obyek.
Process dan Thread Sebuah process adalah tempat/wadah thread berjalan. Proses diberi satu set sumber daya default yang berupa alokasi penggunaan processor dan memori oleh sistem operasi. Didalam process kita dapat membuat satu atau lebih thread. Thread-thread yang berada dalam satu proses dapat memakai sumber daya secara bersama-sama sehingga bisa ada proses komunikasi yang cepat. Bagaimana proses dan thread itu berjalan di core prosessor pembagian kerja prosesor untuk sebuah thread atau thread lainnya adalah urusan sistem operasi. Sebagai programmer kita biasanya tidak mengurusi hal-hal tersebut. Penerapan Multi-Threading
Dalam dunia pemrograman desktop dan mobile, pemrograman multithreading sangat banyak digunakan sementara dalam dunia web proses multithreading sangat sering terjadi tanpa kita menyadarinya. Misal multithreading terjadi ketika browser merender animasi java script sambil menerima data dari internet.
Teknik multithreading sangat disarankan digunakan ketika kita membuat aplikasi game, aplikasi yang menangani file yang ukurannya relatif besar (untuk computer jaman ini kira-kira file yang lebih besar dari 10 MB), aplikasi yang secara intensif berhubungan dengan port komunikasi atau aplikasi yang berhubungan dengan database secara intensif (misal aplikasi yang terus menerus meminta query data untuk mebuat grafik realtime). Contoh perbandingan aplikasi single threading dan multi threading sederhana di Delphi Untuk lebih jelasnya mari kita perhatikan contoh proyek aplikasi delphi berikut. Deskirpsi aplikasi:
Keterangan file csv merupakan file spreadsheet yang tidak berformat yang bisa dibaca oleh software spreadsheet seperti ms-excel. Program ini pertama kali dibuat tanpa teknik multithreading. Kemudian ditangani dengan teknik multithreading agar terbayang bagaimana program multithreading menangani satu masalah yang ada di aplikasi single-threading. Membuat Aplikasi Single-threading
Source file proyek single-threading 1. 2. 3. 4.
Pertama kita buat proyek baru. Di proyek tersebut kita pasang sebuah button dan sebuah savedialog. Edit Caption pada button dengan nama “Buat file”. Edit filter pada save dialog seperti gambar berikut.
5. Kita buat kode seperti berikut. unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm)
Button1: TButton; SaveDialog1: TSaveDialog; procedure Button1Click(Sender: TObject); private { Private declarations } procedure buatFileCSV(namaFile:TFileName); public { Public declarations } end; var Form1: TForm1; implementation uses Math; {$R *.dfm} { TForm1 } { TForm1 } procedure TForm1.buatFileCSV(namaFile: TFileName); var isiFile:TStrings; i,j:Integer; nilaiAcak:Extended; text:String; begin isiFile := TStringList.Create; for i := 1 to 200000 do begin text := 'No. ' + IntToStr(i); for j:=0 to 49 do begin nilaiAcak := sqrt(10 * Random); nilaiAcak := Round(nilaiAcak * 100) / 100; text := text + ',' + FloatToStr(nilaiAcak); end; isiFile.Add(text); end; isiFile.SaveToFile(namaFile); isiFile.Free; end; procedure TForm1.Button1Click(Sender: TObject); begin if SaveDialog1.Execute then buatFileCSV(SaveDialog1.FileName + '.csv'); end;
end. Kode diatas menggambarkan bagaimana kita menyisipkan prosedur buat file dengan nama buat file dan argumen bertipe TFileName di form di bagian private lalu kita panggil kode tersebut di bagian buttonclick dengan memanfaatkan savedialog. Keterangan: * TFileName adalah tipe data turunan dari string yang berfungsi untuk menuliskan path serta nama file. Tipe ini berada di library SysUtils. Biasakan menggunakan tipe ini daripada string ketika menulis nama file karena ada bebera[a fasilitas yang berguna di delphi pada tipe ini. ** Disini kita mengguanakan tipe TStrings (kelas abstract) dan TStringList (kelas turunan konkritnya) untuk mengelola dan menyimpan teks file. Bila anda belum terbiasa dengan tipe ini pelajarilah. Karena tipe ini sangat banyak digunakan di komponen delphi. Compile proyek ini dan akan tertampilkan form dengan button yang ketika kita klik akan menampilkan dialog save. Isi nama file dan perhatikan..... Aplikasi akan membuat file csv sesuai dengan nama dan path yang kita tentukan namun proses ini memakan waktu beberapa lama. Selama proses penulisan maka form aplikasi kita berstatus " Not-Responding". Form akan normal lagi ketika file csv selesai dibuat. Keterangan kenapa terjadi “not-responding” pada aplikasi kita. Di Delphi ketika kita membuat proyek aplikasi windows maka aplikasi yang dibangun oleh Delphi adalah aplikasi single-threading. Terdapat satu thread di aplikasi tersebut yang disebut juga thread utama yang kerjanya adalah meng-scan event-event yang terjadi. Sebagai keterangan Delphi adalah aplikasi yang berjalan secara Event-driven yaitu aplikasi yang proses kerjanya meng-scan event-event yang terjadi secara berurutan(seperti event klik pada button, pergeseran windows dan lain-lain). Bila pada proses scanning ternyata ada event yang terjadi maka proses scanning akan berhenti dan callback (aksi) yang didefinisikan untuk event yang bersangkutan akan dijalankan. Setelah callback/aksi tersebut selesai dijalankan maka proses scanning event berjalan lagi sesuai dengan urutan. Event dan Callback di delphi terdiri dari dua jenis yaitu: 1. Event dan Callback yang sudah tertulis di library Delphi. Seperti ketika kita mengedrag form maka terjadi pergeseran form windows karena terjadi event drag pada title form dan aplikasi mengerjakan callback untuk event drag form, atau perubahan bentuk button ketika ada event click pada button. Di form dan komponen yang kita buat secara otomatis terbuat event-event dan callback standardnya yang terdaftar di aplikasi. Inilah yang menyebabkan kelakuan form menjadi kelakuan standar form GUI (dapat di-drag, di-close dan sebagainya). 2. Event dan Callback yang ditambahkan oleh programmer. Yaitu kode yang kita ketik di bagian event dari komponen atau yang biasa kita tuliskan ketika kita membuat event. Seperti kode di event buttonclick dan sebagainya. Event dan Callback inilah yang menentukan tingkah laku aplikasi sesuai keinginan kita selain kelakuan standar GUI. Ketika kita mengeklik button di aplikasi yang baru kita buat tadi maka callback/aksi pada event buttonclick memanggil proses pembuatan file csv yang kita tambahkan ke event button click. Callback ini cukup berat sehingga proses scan pada event-event di form tidak sempat dijalankan untuk beberapa saat. Ketika kita mengeser form atau mengeklik button maka tidak terjadi apa-apa di form aplikasi kita. Setelah proses pembuatan file csv selesai maka kelakuan form akan kembali
normal. Bagaimana membuat aplikasi yang formnya bebas dari kejadian "not-responding" akan dilakukan dengan teknik multi-threading. Membuat Aplikasi Multi-threading Disini kita akan membangun aplikasi multi-threading sederhana dimana ketika kita mengeklik button maka akan dibuat sebuah thread lain yang berjalan disamping thread utama untuk membuat file csv. Source file proyek multi-threading 1. Kita buat applikasi seperti langkah nomer 1 sampai langkah nomer 4 pada applikasi single-threading. 2. Kita klik File->new->other lalu pilih thread object klik ok dan namakan thread sebagai “BuatCSV”
3. Simpan file thread object yang baru kita buat misal namanya unit2 lalu kita klik form utama. Dan kita klik pada bagian menu file->use unit setelah itu kita pilih file thread object tersebut. Ini menentukan bahwa unit di form utama (misal unit1) mengakses file thread object tadi (unit2) dan kebalikannya tidak.
4.Perhatikan dalam thread object ada procedure Execute. Kode didalam prosedur inilah yang akan dijalankan ketika thread berjalan. procedure BuatCSV.Execute; begin {kode yang ditulis dalam prosedur ini yang akan dijalankan oleh thread} end; 5. Kita edit file thread object (unit2) sebagai berikut: unit Unit2; interface uses Classes, SysUtils; type BuatCSV = class(TThread) private fFileName: TFileName; procedure buatFileCSV(namaFile:TFileName); protected procedure Execute; override;
public property fileName:TFileName read fFileName write fFileName; end; implementation procedure BuatCSV.buatFileCSV(namaFile: TFileName); var isiFile:TStrings; i,j:Integer; nilaiAcak:Extended; text:String; begin isiFile := TStringList.Create; for i := 1 to 200000 do begin text := 'No. ' + IntToStr(i); for j:=0 to 49 do begin nilaiAcak := sqrt(10 * Random); nilaiAcak := Round(nilaiAcak * 100) / 100; text := text + ',' + FloatToStr(nilaiAcak); end; isiFile.Add(text); end; isiFile.SaveToFile(namaFile); isiFile.Free; end; procedure BuatCSV.Execute; begin buatFileCSV(fileName); end; end. Keterangan dari kode diatas.. dibuat variabel fFilename bertipe TFilename untuk menentukan nama file yang disimpan oleh thread ini. private fFileName: TFileName; Dibuat properti untuk mengakses variabel tersebut: public property fileName:TFileName read fFileName write fFileName; Properti ini dibuat agar form utama (unit1) dapat mengirimkan nama file ke thread ini. Dibuat prosedur buatFileCSV untuk membuat file csv dan prosedur tersebut dipanggil di prosedur
execute. dimana argumen/parameter yang digunakan ketika memanggil prosedur buatFileCSV adalah argumen yang dikirimkan oleh form utama melalui properti filename. 6. Di form utama (unit1) kita gunakan dan kode di thread object (unit2):
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; SaveDialog1: TSaveDialog; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation uses Math, Unit2; {$R *.dfm} { TForm1 } procedure TForm1.Button1Click(Sender: TObject); var threadBuatCSV:BuatCSV; begin if (SaveDialog1.Execute) then begin threadBuatCSV := BuatCSV.Create(True); threadBuatCSV.FreeOnTerminate := True; threadBuatCSV.fileName := SaveDialog1.FileName; threadBuatCSV.Resume; end; end;
end. Disitu kita lihat Kelas BuatCSV dipanggil dengan parameter True. Keterangannya adalah parameter True ini berguna agar thread object yang kita buat tidak langsung berjalan tapi idle terlebih dulu. Klo parameter kita set false maka thread object tersebut langsung berjalan padahal kita perlu mengirim parameter filename ke dalam thread tersebut. Kita set property thread menjadi FreeOnTerminate agar ketika thread telah menyelesaikan operasinya maka thread tersebut otomatis hilang dari memori. Setelah parameter filename kita masukkan maka kita panggil fungsi Resume untuk mengaktifkan thread tersebut. 7. Kita compile aplikasi tersebut dan kita jalankan. Akan kita lihat ketika kita telah mengeklik tombol save didialog button maka form tetap berjalan normal dan proses pembuatan file csv tetap berjalan seperti biasa. Penutup Ketika thread utama membuat thread lain atau thread pekerja maka thread utama bisa dikatakan lepas tangan dan thread pekerja bekerja sendiri secara independen. Seperti yang ditunjukkan oleh aplikasi tersebut. Thread pengontrol atau thread utama dapat membuat, memulai, menghentikan (pause atau halt) obyek thread lainnya. Namun dia tidak bisa turut campur lebih jauh ke kerja dari intruksi-intruksi dalam thread lain tersebut. Aplikasi yang kita buat tersebut adalah aplikasi multithread sederhana dimana kita tidak bisa melihat status dari yang dikerjakan oleh thread pekerja(Thread yang membuat file csv). Bagaimana bila kita ingin membuat status pekerjaan thread tersebut bisa ditampilkan di form gui, misal dengan sebuah progressbar yang diakses oleh thread pekerja, sementara form gui diatur oleh thread utama. Ini bisa kita lakukan namun sebelumnya kita harus mengerti tentang tingkah laku beberapa thread yang mengakses satu atau lebih sumber daya (resource) variable atau obyek bersama-sama dan masalah-masalah yang mungkin ditimbulkan. Satu metode yang lazim digunakan adalah sinkronisasi kerja thread. Saya sendiri berencana untuk membuat tutorialnya segera, semoga cepat terlaksana :D.
Tentang Penulis Catur Budi Santoso Freelance.