Delay dan select

Penundaan waktu dengan delay dan penerimaan entry selektif melalui select.

Daftar isi

Konkurensi memerlukan kontrol waktu, mulai dari menunda eksekusi beberapa puluh milidetik hingga menunggu kejadian dengan batas tertentu. Ada menyediakan pernyataan delay untuk penundaan dan pernyataan select untuk menunggu salah satu dari beberapa alternatif, termasuk penerimaan entry selektif. Topik ini membahas keduanya beserta panggilan entry berbatas waktu dan panggilan entry bersyarat.

Pernyataan delay#

Pernyataan delay menerima durasi bertipe Duration dalam satuan detik, misalnya delay 0.1; untuk penundaan sepersepuluh detik, dan sah pada task maupun subprogram biasa. Tipe ini berupa bilangan titik tetap, sehingga penundaan pecahan ditulis langsung dalam detik tanpa konversi satuan. Penundaan dijamin berlangsung sekurang-kurangnya selama durasi itu, sedangkan durasi sesungguhnya bergantung pada penjadwal sistem. Penundaan berdurasi nol tetap berfungsi sebagai titik penjadwalan yang memberi kesempatan task lain bertindak.

Bentuk delay until menerima nilai waktu alih-alih durasi, sehingga cocok untuk jadwal siklik yang acuannya tetap. Program berikut mencatat tiga ketukan dengan jeda sepersepuluh detik di antaranya.

ada ketukan.adb
with Ada.Text_IO;

procedure Ketukan is
begin
   for I in 1 .. 3 loop
      Ada.Text_IO.Put_Line ("ketukan" & Integer'Image (I) & " dicatat");
      delay 0.1;
   end loop;
end Ketukan;
bash
# kompilasi program
gnatmake -q ketukan.adb
# jalankan program
./ketukan
text Keluaran
ketukan 1 dicatat
ketukan 2 dicatat
ketukan 3 dicatat

Baris keluaran tercetak dengan jarak sekitar 100 milidetik, dan urutannya pasti karena program ini tidak memiliki task lain. Untuk jadwal yang intervalnya tidak boleh bergeser, acuan delay until dihitung dari jam nyata Ada.Real_Time.Clock dan ditambah satu periode tetap pada setiap siklus, sehingga lama pekerjaan tidak terakumulasi ke interval berikutnya. Pola itu diwajibkan pada profil Ravenscar.

Penerimaan selektif dengan select#

Task yang memiliki lebih dari satu kebutuhan tunggu tidak perlu mengantre entry satu per satu. Pernyataan select pada badan task menawarkan beberapa alternatif sekaligus, misalnya accept yang dipasangkan dengan delay sebagai batas tunggu. Task menunggu sampai salah satu alternatifnya siap, lalu mengeksekusi pilihan itu saja. Alternatif accept siap apabila ada pemanggil yang sudah mengantre pada entry tersebut, sedangkan alternatif delay siap setelah waktunya tiba. Apabila dua alternatif siap pada saat yang sama, bahasa tidak menentukan pilihannya, sehingga desain tidak boleh bergantung pada urutan pilihan tersebut.

Program berikut membuat task Antena menunggu sinyal dengan batas waktu 0.3 detik, sedangkan program utama mengirimkan panggilan setelah 0.1 detik.

ada penerima_tepat.adb
with Ada.Text_IO;

procedure Penerima_Tepat is
   task Antena is
      entry Tiba;
   end Antena;

   task body Antena is
   begin
      select
         accept Tiba;
         Ada.Text_IO.Put_Line ("antena: sinyal diterima");
      or
         delay 0.3;
         Ada.Text_IO.Put_Line ("antena: batas waktu tercapai");
      end select;
   end Antena;
begin
   delay 0.1;
   Antena.Tiba;
end Penerima_Tepat;
bash
# kompilasi program
gnatmake -q penerima_tepat.adb
# jalankan program
./penerima_tepat
text Keluaran
antena: sinyal diterima

Panggilan Tiba datang lebih dulu daripada batas waktunya, sehingga alternatif accept terpilih dan penanganan sinyalnya dieksekusi. Program utama melanjutkan eksekusinya setelah rendezvous selesai. Bentuk selective accept semacam ini lazim pada task layanan yang harus tetap peka terhadap perintah sambil menunggu pekerjaan utamanya.

Pilihan ketika sinyal tak datang#

Task yang sama menunjukkan pilihan lain apabila tidak ada panggilan sebelum batas waktunya. Program berikut membiarkan task Antena menunggu tanpa panggilan sama sekali, dan program utama hanya menunggu tasknya berhenti.

ada penerima_lambat.adb
with Ada.Text_IO;

procedure Penerima_Lambat is
   task Antena is
      entry Tiba;
   end Antena;

   task body Antena is
   begin
      select
         accept Tiba;
         Ada.Text_IO.Put_Line ("antena: sinyal diterima");
      or
         delay 0.3;
         Ada.Text_IO.Put_Line ("antena: batas waktu tercapai");
      end select;
   end Antena;
begin
   null;
end Penerima_Lambat;
bash
# kompilasi program
gnatmake -q penerima_lambat.adb
# jalankan program
./penerima_lambat
text Keluaran
antena: batas waktu tercapai

Alternatif delay terpilih karena 0.3 detik terlampaui tanpa panggilan, dan task berhenti setelah penanganannya selesai. Batas tunggu pada select berlaku untuk satu evaluasi saja. Karena itu, task layanan yang menunggu berulang memasang pernyataan select di dalam perulangan, dan setiap perulangan memiliki batas waktunya sendiri. Karena bagian penanganan batas waktunya dapat mencatat kejadian atau menyiapkan percobaan berikutnya, pola ini cocok untuk sinyal yang kehadirannya tidak pasti, misalnya detak alat yang dapat terputus. Kedua program pada topik ini hanya memiliki satu hasil seleksi per eksekusi, sehingga keluarannya tetap dapat diprediksi meskipun seleksinya melibatkan waktu.

Timed dan conditional entry call#

Batas waktu juga dapat dipasang pada sisi pemanggil melalui timed entry call. Bentuknya berupa select yang memuat satu panggilan entry yang dipasangkan dengan delay, dan timernya berlaku selama panggilan masih mengantre. Rendezvous yang sudah dimulai tidak dapat dibatalkan oleh timer karena kedua task sudah terikat pada aksi yang sama. Bentuk tanpa timer bernama conditional entry call, yang menggunakan alternatif else dan tidak menunggu sama sekali apabila panggilannya tidak langsung diterima.

Program berikut meniru antrean tiket loket. Task Pembeli_Pertama dilayani dengan rendezvous yang berlangsung 0.5 detik, sedangkan program utama mencoba membeli setelah 0.1 detik dengan batas tunggu 0.1 detik.

ada antrean_loket.adb
with Ada.Text_IO;

procedure Antrean_Loket is
   task Loket is
      entry Beli (Jumlah : in Integer; Total : out Integer);
   end Loket;

   task body Loket is
   begin
      accept Beli (Jumlah : in Integer; Total : out Integer) do
         delay 0.5;
         Total := Jumlah * 15000;
      end Beli;
   end Loket;

   task Pembeli_Pertama;

   task body Pembeli_Pertama is
      Total : Integer;
   begin
      Loket.Beli (3, Total);
      Ada.Text_IO.Put_Line ("pembeli pertama membayar" & Integer'Image (Total));
   end Pembeli_Pertama;

   Total : Integer;
begin
   delay 0.1;
   select
      Loket.Beli (2, Total);
      Ada.Text_IO.Put_Line ("pembeli kedua membayar" & Integer'Image (Total));
   or
      delay 0.1;
      Ada.Text_IO.Put_Line ("antrean lambat, pemesanan kedua dibatalkan");
   end select;
end Antrean_Loket;
bash
# kompilasi program
gnatmake -q antrean_loket.adb
# jalankan program
./antrean_loket
text Keluaran
antrean lambat, pemesanan kedua dibatalkan
pembeli pertama membayar 45000

Panggilan program utama mengantre karena loket sedang melayani pembeli pertama. Timer 0.1 detiknya habis sebelum rendezvous dimulai, sehingga alternatif pembatalannya yang dieksekusi. Pembeli pertama selesai sesudahnya dan melaporkan total belanjanya. Urutan kedua baris itu pasti karena keduanya terjadi pada waktu yang berbeda, yaitu sekitar 0.2 detik dan 0.5 detik. Bentuk bersyaratnya hanya mengganti delay dengan else.

ada Contoh: conditional entry call tanpa penantian
-- tidak-dijalankan
select
   Loket.Beli (2, Total);
   Ada.Text_IO.Put_Line ("pembelian berhasil");
else
   Ada.Text_IO.Put_Line ("loket sedang melayani");
end select;

Kesalahan umum#

Tiga kekeliruan berikut sering muncul saat delay dan select dipraktikkan.

  • Menganggap delay presisi. Pernyataan itu menunda sekurang-kurangnya selama durasinya, sedangkan durasi sesungguhnya dapat lebih panjang pada sistem yang sibuk. Jadwal yang intervalnya tidak boleh bergeser menggunakan delay until dengan acuan tetap, bukan delay relatif yang diulang.
  • Memasang timer pada panggilan yang rendezvous-nya sudah dimulai. Timer hanya membatalkan panggilan yang masih mengantre, sehingga aksi di dalam accept tetap selesai. Rancang durasi layanan agar sesuai batas yang dijanjikan kepada pemanggil.
  • Menulis select yang seluruh alternatifnya tanpa batas waktu dan tanpa else. Task semacam itu dapat menunggu selamanya apabila tidak ada panggilan yang datang. Pasangkan satu alternatif delay sebagai batas tunggu.

Ringkasan#

  • Pernyataan delay menunda eksekusi sekurang-kurangnya selama durasinya, sedangkan delay until menunggu sampai waktu acuannya tercapai.
  • Select pada badan task menunggu salah satu alternatifnya, dan alternatif delay memberi batas tunggu pada penerimaan entry.
  • Timed entry call membatalkan panggilan yang masih mengantre ketika waktunya habis, sedangkan conditional entry call tidak menunggu sama sekali.

Referensi#