Kesalahan Multithread? – Bagian I

Beberapa hari berkutat dengan masalah yang sebenernya sederhana (ini tahunya belakangan :D), tapi mencari solusi yang kelewat kompleks (menurut saya).

Masalah pertama adalah kecurigaan terhadap kesalahan thread dari program yang saya buat (hehehe emang enak nyalahin orang lain – baca: program) ketika terjadi kondisi di akhir thread terhadap suatu proses yang diharapkan, tetapi harapan tersebut tidak terjadi. Hmm bingung ya? Paragraf berikut ini berusaha menerangkan kasus yang terjadi.

Saya memiliki 2 komponen yang saling berinteraksi, masing – masing berjalan dengan thread yang berbeda, masing-masing adalah:

·         Komponen pertama K1 memiliki tugas yang sangat sederhana yaitu menuliskan hasil parse data mentah DM1 menjadi data yang valid DV1 yang disimpan ke dalam antrian Q1, ke dalam suatu file F1. DV1 sendiri merupakan data tunggal yang ada di dalam suatu antrian (yang berharap ditulis ke dalam file) Q1, sehingga di dalam Q1 terdapat DV11, DV12, sampai DV1n. Aturan yang saya buat adalah akan menulis ke dalam file F1 jika satu atau lebih kondisi berikut terpenuhi (menggunakan relasi “atau” – or):

1.       Jika jumlah DV1 di dalam antrian Q1 adalah lebih besar atau sama dengan nilai tertentu yang dapat dikonfigurasi.

2.       Jika jumlah DM1 lebih kecil atau sama dengan 0.

Karena proses penulisan ke dalam file yang dilakukan oleh K1 berada dalam thread yang terpisah dari thread utama, maka proses ini akan dilakukan terus selama tidak ada signal dari thread utama untuk mengakhiri proses.

·         Komponen kedua K2. Memiliki tugas juga sangat sederhana, yaitu membuka setiap file yang telah ditulis oleh K1 dan melakukan proses konversi menjadi data lain yang diinginkan, sebut saja DV2. Selanjutnya di dalam K2 ini juga kumpulan hasil konversi akan disubmit menggunakan Web Service, tetapi ini tidak akan dibahas di tulisan ini karena memang bukan permasalahan yang berhubungan dengan thread.

Thread ini juga merupakan anakkan dari thread utama seperti halnya thread terhadap K1. Di dalam K2 saya menggunakan satu komponen lain yang melakukan pengamatan terhadap folder dimana F1 akan dituliskan – merupakan enkapsulasi dari satu kelas standar di dalam .NET yang disebut “FileSystemWatcher”. Di dalam folder tersebut akan terdapat lebih dari satu F1, sebut saja F11, F12, sampai F1n.

Harapan saya terhadap komponen ini adalah apabila terdapat penambahan file yang dihasilkan K1 akan dapat masuk ke dalam antrian untuk diproses.

Kondisi yang akan dijalankan oleh thread ini adalah:

1.       Jika signal berhenti belum diterima.

2.       Jika jumlah F1 yang belum diproses lebih besar dari 0.

Sperti halnya K2, maka K1 akan berhenti jika mendapat signal dari thread utama.

Ok, mudah-mudahan masih mudeng, sebelumnya mohon maaf, tulisan ini bukan tulisan yg pop karena ga ngebahas LINQ, ADEM, dll yang lagi ngetrend :D. Back to business…

Harapan saya adalah ketika thread utama mengirimkan signal bahwa proses telah selesai (di trigger dari luar sistem) maka semua file yang berada di dalam folder yang diamati oleh K2 akan diproses. Kenyataanya adalah bahwa ketika signal proses selesai telah dikirim, maka secara “berurutan” thread K1 akan melakukan “Join” – menyelesaikan masalah2 yg belum tuntas, lalu K2 juga demikian. Tetapi apa yang terjadi?

1.       Ketika K1 menyelesaikan masalahnya, maka ada beberapa F1  yang akan di buat oleh nya. Harapan saya adalah semua F1 yang dibuat pada masa-masa akhir ini akan dikonsumsi oleh K2.

2.       Ketika K2 menyelesaikan masalahnya, ternyata tidak satupun F1 yang dibuat pada “injury time” ini yang diproses.

Hmmm, saya berulang kali menyalahkan algoritma yang ada pada K1 dan K2 (padahal saya sendiri yang membuatnya). Kecurigaan pada proses signaling sampai kesimpulan “Ini pasti bug nya VS 2008” :D. Sampai tadi malam saya berpikir kembali, lalu melihat algoritma yang ada pada thread utama ketika melakukan penyelesaian proses. Melihat, berpikir sebentar, lalu saya tertawa, dan berlari ke kamar menemui istri saya yang sedang tertidur, lalu berkata “Ternyata bukan salah threadnya…., hahaha ini salah saya menuliskan algoritma di dalam thread utama”.

Apa yang sebenarnya terjadi di dalam thread utama yang menyebabkan kesalahan fatal diatas? Sebelum menuju masalah mari kita lihat apa yang biasanya dilkaukan terhadap suatu aplikasi multi thread ketika mengakhiri aplikasi?

1.       Mengirimkan signal ke semua thread untuk mengakhiri proses.

2.       Melakukan join.

Dua konsep sederhana diatas jika ditulisakan dalam algoritma yang salah akan berakibat fatal (tidak sesuai dengan apa yang diharapkan, walaupun aplikasi berakhir secara normal).

Kesalahan yang saya lakukan adalah dengan algoritma berikut:

  1. Mengirimkan signal ke semua thread K1 yang sedang berjalan untuk mengakhiri proses. (langkah ini adalah benar dilakukan pertama kali).
  2. Mengirimkan signal ke semua thread K2 untuk mengakhiri proses. (Inilah kesalahannya, karena thread K2 akan langsung berhenti karena tidak ada lagi F1x yang diproses).
  3. Melakukan join pada semua thread K1. Sehingga pada saat ini K1 akan menuliskan DVx sejumlah m yang tersisa menjadi F1x sejumlah m pula.
  4. Melakukan join pada semua thread K2. Disini diharapkan melakukan proses terhadap F1x sejumlah m, tetapi tidak terjadi karena sudah keluar dari kondisi untuk melakukan proses akibat dari point 2 diatas.

Lalu apa yang dilakukan?

  1. Proses ini benar.
  2. Melakukan join thread K1, sehingga akan menuliskan semua file F1x yang tersisa. Di sisi lain karena K2 masih berjalan, maka setiap penambahan file akan disimpan dalam antrian K2.
  3. Mengirim signal ke semua thread K2 untuk berhenti. Kondisi proses akan tetap dilakukan di dalam K2, karena masih ada file yang tersimpan di dalam antrian menunggu untuk dip roses.
  4. Melakukan join, menyelesaikan semua proses terhadap F1x.

Pelajaran apa yang bisa didapat?

1.       Bagi saya adalah menganggap sepele permasalahan yang sebenarnya memang sepele tanpa logika yang kuat akan berakibat fatal.

2.       Terlalu cepat mengambil kesimpulan sehingga menyalahkan hal lain yang belum tentu salah tanpa bukti yang kuat, akan berakibat fatal juga.

3.       Akhirnya, mencoba menjernihkan pikiran kembali, dan mengamati masalah dari akarnya (thread utama), melakukan investigasi secara teliti dan berurutan.

Wallohu a’lam.

 

Share this post: | | | |

Comments

# Maulida said:

stuju sama point terakhir... (pelajaran yg didapat)... been there.. :P

Wednesday, April 09, 2008 1:27 PM
# apria said:

hehe..bagus deh udh selesai..

sampai pusing berat yah

:)

Wednesday, April 09, 2008 3:35 PM
# basir said:

4 Istriku: Termasuk mencatat setiap kesalahan yg perna dilakukan, kapan perlu tinggal liat catetan.

4 Apria: Masi ada satu masalah lagi Pri, Insya Allah di bagian II :D

Wednesday, April 09, 2008 3:46 PM
# daru said:

Bagian I aja pusing.. apalagi bagian II :p

Tapi pasti ada pelajaran yang di dapet.. :)

Di tunggu Bagian II (lama2 bikin novel nih...AAB=Ayat Ayat Basir)

Wednesday, April 09, 2008 4:18 PM
# De_Joker said:

Bos....akan sangat membantu sekali untuk membacanya kalo dibikin gambarnya :P gambar sederhana aja kekeke

Wednesday, April 09, 2008 7:50 PM
# basir said:

2 Daru: Pusingnya ga sberapa Ru, gondoknya yg beberapa :p

2 De Joker: Wah bener Mas Joker, mudah2an saya bisa mem-visualisasikannya. Kayanya perlu Bagian 1A sebelum Bagian 2.

Thursday, April 10, 2008 5:58 AM
# daru said:

Mana nih, Bagian II nya..(ditunggu...)

Jangan2.. pusing nulisnya gimana...he9x

Monday, April 14, 2008 7:03 PM
# basir said:

2 Daru: Hehehe, bagian 2 ntar nyusul, nulis yg lain dulu deh ;)

Tuesday, April 15, 2008 7:56 AM