Data bersama yang diakses beberapa task sekaligus memerlukan aturan akses yang dijamin bahasa, bukan sekadar kedisiplinan penulis kode. Ada menyediakan protected object, yakni unit yang mengenkapsulasi data bersama dan menjamin setiap aksinya dieksekusi secara eksklusif. Topik ini membahas protected procedure, protected function, protected entry dengan barrier, serta batasan yang berlaku di dalam aksi terlindungi.
Masalah data bersama#
Penambahan sederhana pada penghitung sebenarnya terdiri atas tiga langkah, yaitu membaca, mengubah, dan menulis, yang ketiganya dapat tercampur antar task. Apabila dua task menambah penghitung yang sama hampir bersamaan, keduanya dapat membaca nilai lama sehingga satu penambahan hilang. Misalnya, penghitung bernilai 10, kedua task membaca nilai itu, lalu masing-masing menulis 11, padahal hasil yang benar adalah 12. Kebanyakan bahasa menyerahkan penanganan kepada kunci yang harus dipasang dan dilepas secara manual, dan satu jalur kode yang lupa mengunci saja sudah cukup untuk merusak data. Ada mengatur hal ini pada tingkat bahasa melalui protected object, sehingga tidak ada kunci yang perlu dipasang secara manual dan eksklusivitas aksi dijamin langsung oleh bahasa.
Data pada protected object ditempatkan di bagian private, sehingga tidak dapat dibaca maupun ditulis langsung dari luar. Seluruh akses harus melalui operasi terlindungi yang dinyatakan pada spesifikasinya. Penyembunyian data ini sejajar dengan tipe privat pada package, tetapi ditambah jaminan bahwa operasi terlindungi tidak berjalan tumpang tindih.
Tiga bentuk operasi terlindungi#
Spesifikasi protected object memuat tiga bentuk operasi yang masing-masing memiliki aturan eksekusi berbeda. Tabel berikut merangkum ketiganya.
| Bentuk | Eksekusi | Peran |
|---|---|---|
| protected procedure | eksklusif terhadap semua aksi | membaca dan mengubah data terlindungi |
| protected function | boleh bersamaan dengan fungsi lain | hanya membaca data terlindungi |
| protected entry | eksklusif dengan syarat barrier | menunggu syarat sebelum aksinya dijalankan |
Protected procedure dan protected function dieksekusi tanpa menunggu syarat, sedangkan protected entry memeriksa barrier, yaitu ekspresi boolean yang ditulis pada badan entry tersebut. Program berikut menggunakan protected procedure dan protected entry pada satu protected object bernama Rekap. Objek tersebut menerima pembacaan dari dua alat dan menyerahkan totalnya setelah empat nilai terkumpul.
with Ada.Text_IO;
procedure Rekap_Sensor is
protected Rekap is
procedure Simpan (Nilai : in Integer);
entry Ringkas (Total : out Integer);
private
Jumlah_Datang : Natural := 0;
Total_Sensor : Integer := 0;
end Rekap;
protected body Rekap is
procedure Simpan (Nilai : in Integer) is
begin
Total_Sensor := Total_Sensor + Nilai;
Jumlah_Datang := Jumlah_Datang + 1;
end Simpan;
entry Ringkas (Total : out Integer) when Jumlah_Datang = 4 is
begin
Total := Total_Sensor;
end Ringkas;
end Rekap;
task Alat_A;
task body Alat_A is
begin
Rekap.Simpan (21);
Rekap.Simpan (23);
end Alat_A;
task Alat_B;
task body Alat_B is
begin
Rekap.Simpan (20);
Rekap.Simpan (24);
end Alat_B;
Total : Integer;
begin
Rekap.Ringkas (Total);
Ada.Text_IO.Put_Line ("total pembacaan:" & Integer'Image (Total));
end Rekap_Sensor;# kompilasi program
gnatmake -q rekap_sensor.adb
# jalankan program
./rekap_sensortotal pembacaan: 88Kedua task alat memanggil Simpan tanpa urutan yang pasti, tetapi setiap pemanggilan tetap tereksekusi satu per satu karena aksi terlindunginya saling eksklusif. Program utama menunggu pada entry Ringkas yang barrier-nya menuntut empat penyimpanan, sehingga total yang diterima selalu 88 tanpa bergantung pada kecepatan masing-masing task. Penjumlahan empat nilai menjadi aman tanpa satu baris kunci pun ditulis.
Entry dengan barrier#
Barrier menentukan apakah pemanggil entry boleh masuk atau harus mengantre. Ekspresi barrier dievaluasi pada saat panggilan diantrekan dan kembali dievaluasi setiap kali sebuah aksi terlindungi selesai, sehingga pemanggil yang tadinya mengantre dapat dilayani begitu barrier terbuka. Apabila beberapa task mengantre pada entry yang sama, bahasa menjamin salah satu pemanggil terpilih setiap kali barrier membuka, tetapi urutan pemilihannya kembali tidak dijamin.
Barrier dibatasi pada ekspresi boolean sederhana, sehingga kebutuhan tunggu yang berbeda disusun sebagai beberapa entry dengan barrier masing-masing, misalnya antrean tiket loket yang syaratnya sisa tiket belum habis. Pola ini menggantikan perulangan tunggu manual yang terus menghabiskan waktu prosesor. Program berikut memasangkan satu task produsen dengan satu task konsumen melalui protected object Sinyal.
with Ada.Text_IO;
procedure Lintas_Sinyal is
protected Sinyal is
entry Ambil (Nilai : out Integer);
procedure Isi (Nilai : in Integer);
private
Terisi : Boolean := False;
Data : Integer := 0;
end Sinyal;
protected body Sinyal is
entry Ambil (Nilai : out Integer) when Terisi is
begin
Nilai := Data;
Terisi := False;
end Ambil;
procedure Isi (Nilai : in Integer) is
begin
Data := Nilai;
Terisi := True;
end Isi;
end Sinyal;
task Produsen;
task body Produsen is
begin
Sinyal.Isi (42);
end Produsen;
task Konsumen;
task body Konsumen is
Hasil : Integer;
begin
Sinyal.Ambil (Hasil);
Ada.Text_IO.Put_Line ("konsumen menerima nilai" & Integer'Image (Hasil));
end Konsumen;
begin
null;
end Lintas_Sinyal;# kompilasi program
gnatmake -q lintas_sinyal.adb
# jalankan program
./lintas_sinyalkonsumen menerima nilai 42Apabila task konsumen lebih dulu mencapai Ambil, barrier Terisi masih False sehingga panggilannya mengantre sampai Isi selesai. Apabila produsen lebih dulu memanggil Isi, barrier sudah terbuka dan panggilan itu langsung dilayani. Kedua kemungkinan menghasilkan keluaran yang sama, dan penyerapan satu nilai ditangani tanpa perulangan tunggu sama sekali.
Batasan aksi terlindungi#
Aksi terlindungi harus pendek dan tidak boleh memblokir karena satu aksi yang berlarut menahan seluruh task lain yang hendak mengakses objek yang sama. Panggilan entry pada task, rendezvous, dan pernyataan delay dilarang di dalam protected procedure, protected function, maupun protected entry. GNAT menandai pelanggaran semacam itu melalui peringatan pada saat kompilasi, sehingga aksi yang berpotensi memblokir dapat dideteksi lebih dahulu. Komunikasi keluar dari protected object dilakukan dengan menyimpan hasil pada bagian private, kemudian task lain mengambilnya melalui operasi terlindungi tersendiri.
Sistem waktu nyata menambahkan satu jaminan lagi, yaitu protokol priority ceiling yang menaikkan prioritas task pemanggil ke prioritas ceiling objek terlindungi selama aksinya berlangsung, sehingga inversi prioritas terkendali. Dengan protokol itu, waktu tunggu terpanjang pada protected object dapat dihitung dari durasi aksinya. Jaminan ini menjadi salah satu fondasi profil Ravenscar yang memperketat seluruh model tasking.
Kesalahan umum#
Empat kekeliruan berikut sering muncul saat protected object dipraktikkan.
- Menempatkan operasi yang memblokir di dalam aksi terlindungi. GNAT melaporkannya dengan peringatan
potentially blocking operation in protected operationpada saat kompilasi. Pindahkan komunikasi tersebut ke task dan biarkan protected object hanya menyimpan data. - Mengubah data pada protected function. Kompilator menolak penugasan terhadap data private di dalam protected function, dan bentuk ini memang disediakan untuk pembacaan saja. Gunakan protected procedure apabila data perlu diubah.
- Mengubah variabel penentu barrier dari luar protected object. Barrier hanya dievaluasi ulang setelah aksi terlindungi, sehingga perubahan dari luar tidak berdampak pada antrean. Simpan seluruh state penentu barrier di bagian private dan ubah melalui aksinya.
- Menulis aksi terlindungi yang berlarut. Eksklusivitas berarti satu aksi yang panjang menahan seluruh task lain yang menunggu objek yang sama. Pindahkan pekerjaan berat ke dalam task, dan sisakan protected object untuk penyerahan data yang pendek.
Ringkasan#
- Protected object mengenkapsulasi data bersama pada bagian private dan menjamin aksinya dieksekusi secara eksklusif tanpa kunci manual.
- Protected procedure menulis data, protected function hanya membaca, sedangkan protected entry menunggu barrier terbuka sebelum dieksekusi.
- Barrier dievaluasi ulang setiap aksi terlindungi selesai, dan aksi terlindungi tidak boleh memblokir karena akan menahan task lain.
Referensi#
- 9.4 Protected Units and Protected Objects — Ada Reference Manual 2022 — Menetapkan semantik aksi terlindungi, barrier, dan eksklusivitas aksesnya.
- Idioms for Protected Objects — Ada in Practice, AdaCore — Mengumpulkan pola pemakaian protected object yang lazim dipakai.
- Tasking — Introduction to Ada, AdaCore — Memperkenalkan protected object berdampingan dengan task dan rendezvous.