Notes tentang Semaphore Anung B. Ariwibowo 17 Juli 2009
Daftar Isi 0.1 0.2 0.3 0.4 0.5
0.1
First Things First . . . . Mengkompilasi Program Shared Memory . . . . . What next? . . . . . . . Petunjuk akhir . . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
1 1 2 6 7
First Things First
Apa yang perlu anda lakukan pertama kali? Ubahlah password anda di mesin pascal. Gunakan perintah: passwd Ikuti perintah yang diberikan. Hal yang perlu diingat, jangan melupakan password yang sudah anda ubah. Sselanjutnya, sebelum anda dapat melakukan tugas program ini, salinlah template program yang sudah tersedia ke home-directory anda dengan perintah berikut: cp -R /usr/local/semafor/* . Kemudian anda dapat mulai mengerjakan tugas program dengan melakukan modifikasi terhadap berkas producer.c atau consumer.c, tergantung dari peran anda dalam kelompok.
0.2
Mengkompilasi Program
Dalam direktori /usr/local/semafor yang anda buat salinannya ke home-directory anda, terdapat sebuah berkas Makefile yang dapat anda gunakan untuk memudahkan anda dalam mengkompilasi program. Untuk melakukan kompilasi, anda cukup mengetikkan perintah make 1
0.3. SHARED MEMORY pada command-line. Setiap kali anda membuat perubahan pada berkas producer.c atau consumer.c, anda cukup mengetikkan perintah make di atas untuk melakukan kompilasi.
0.3
Shared Memory
Sesuai dengan namanya, shared memory merupakan area memori yang dibagipakai oleh satu atau lebih proses. Untuk memberikan gambaran, bayangkan ada dua buah proses yang sedang berjalan di memori komputer, di samping proses kernel, seperti ilustrasi berikut: +----------+ | . . . . .| | . free .| | memory .| | . . . . .| | . . . . .| |----------| | | | producer | | | |----------| | | | consumer | | | |----------| | | | kernel | | | +----------+ Ilustrasi ini tidak menggambarkan kondisi sebenarnya. Dalam kondisi nyata, terdapat jauh lebih banyak proses yang sedang berjalan dalam satu saat. Kapan shared memory tercipta? Di mana letak shared memory tersebut? Sebuah shared memory pada dasarnya dapat dibuat oleh proses apapun, tidak peduli itu user process atau system process. Untuk tugas kita ini, yang membuat shared memory bisa producer atau consumer, tergantung dari siapa yang lebih dahulu dijalankan. Sekarang misalkan saja producer yang lebih dulu dijalankan 2
0.3. SHARED MEMORY
dan membuat shared memory (dengan memanggil system-call shmget() ). Karena shmget() adalah system-call, maka yang menjalankan aksi sebenarnya dalam pembuatan shared memory adalah kernel. Sebagai sebuah proses, kernel tidak dapat mengakses area memori di luar kernel, karenanya shared memory akan dibuat sebagai bagian dari proses kernel: +----------+ | . . . . .| | . free .| | memory .| | . . . . .| | . . . . .| |----------| | | | producer | | | |----------| | | | consumer | | | |----------| | kernel | |+--------+| || shared || || memory || |+--------+| +----------+ Berapa byte besarnya shared memory yang berhasil dibuat? (asumsikan saja untuk sementara ketika memanggil shmget(), tidak ada kesalahan yang terjadi) Besarnya area shared memory yang tercipta tergantung dari nilai argumen kedua yang diberikan oleh producer ketika memanggil shmget(). Angka yang diberikan sebagai argumen kedua ini dihitung dalam satuan byte. Bila anda mengetikkan int shmid; shmid = shmget(1292, 12, IPC_CREAT|IPC_EXCL|0666); maka akan tercipta shared memory di dalam kernel Linux sebesar 12 byte.
3
0.3. SHARED MEMORY
Kalau shared memory menjadi bagian dari kernel, lalu bagaimana caranya producer dapat mengakses shared memory tersebut? Gunakan system-call shmat(). Ketika berhasil memanggil system-call shmget(), producer akan mendapatkan suatu nilai sebagai return-value dari shmget(), dalam contoh pemanggilan di atas disimpan dalam variabel shmid. Nilai shmid ini digunakan untuk memanggil system-call shmat(). char* segptr; segptr = (char *) shmat (shmid, 0, 0); Untuk tugas ini, argumen kedua dan ketiga dari shmat() cukup menggunakan nilai 0. Sekali lagi, untuk sederhananya penjelasan, anggap saja pemanggilan shmat() sukses tanpa kesalahan apapun; variabel segptr, yang bertipe pointer-to-char, akan berisi alamat dari area shared-memory di dalam kernel linux: +----------+ | . . . . .| | . free .| | memory .| | . . . . .| | . . . . .| |----------| | producer | |+--------+| || segptr |----+ |+--------+| | |----------| | | | | | consumer | | | | | |----------| | | kernel | | |+--------+| | || shared || | || memory |<---+ || || |+--------+| +----------+
4
0.3. SHARED MEMORY
Nah, sekarang producer dapat dengan mudah menggunakan shared memory tersebut. Caranya? segptr di dalam producer akan berlaku seperti sebuah array. Karena shared memory dibuat sebesar 12 byte, dan segptr dideklarasikan sebagai pointer-to-char, maka seolah-olah segptr berlaku seperti sebuah array-of-char yang jumlah anggotanya ada 10. Perhatikan: Jika anda mendeklarasikan segptr sebagai pointer-to-int, seperti berikut: int* segptr; segptr = (int *) shmat (shmid, 0, 0);
maka segptr akan berlaku seperti sebuah array-of-int yang jumlah anggotanya ada 3. Karena segptr berlaku seperti array-of-char, maka anda dapat mengisi sharedmemory tersebut dengan mudah menggunakan sebuah assignment statement: for (int ii=0; ii<10; ii++) segptr[ii] = ’a’; For-loop di atas akan mengisi seluruh shared-memory dengan huruf ’a’. Misalkan saja sekarang anda menjalankan program consumer. Ketika pertama kali mulai, consumer akan berusaha membuat shared memory dengan key yang sama dengan producer. Karena producer sebelumnya telah berhasil membuat shared memory, maka kernel akan memberitahukan kepada consumer bahwa sudah ada yang pernah membuat shared memory dengan key yang sama. Berdasarkan informasi ini, maka consumer akan meng-attach-kan shared memory yang telah dibuat oleh producer tersebut, sehingga sekarang ilustrasi layout memori akan tampak seperti ini: +----------+ | . . . . .| | . free .| | memory .| | . . . . .| | . . . . .| |----------| 5
0.4. WHAT NEXT?
| producer | |+--------+| || segptr |----+ |+--------+| | |----------| | | consumer | | |+--------+| | +---| segptr | | | |+--------+| | | |----------| | | | kernel | | | |+--------+| | | || shared || | +-->| memory |<---+ || || |+--------+| +----------+ Dan ketika mengakses isi shared memory, consumer akan melihat bahwa shared memory semuanya berisi karakter ’a’.
0.4
What next?
Sampai di sini, pertanyaan berikutnya adalah, bagaimana konsep ini dapat digunakan untuk mengerjakan tugas producer-consumer? Hal pertama yang harus anda pahami adalah, shared memory dapat kita gunakan untuk mensimulasikan buffer (ingat analogi piring di kelas) yang ingin anda implementasikan dalam tugas. Berapa jumlah ”piring” yang ingin anda buat? Misalkan saja 5 buah ”piring”. Ini berarti minimum anda harus membuat shared-memory sebesar 5 byte (untuk mudahnya, gunakan saja tipe data char untuk mengisi ”piring-piring” kita. Jadi kita punya ’restoran’ dengan masakan khas ’char’. Manalagi selain di Trisakti?). Hal berikutnya yang harus anda perhitungkan adalah selain 5 buah ”piring” yang diperlukan untuk menyimpan ’char’ yang sudah matang, anda harus membuat setidaknya dua buah ’papan pengumuman’. ’Papan pengumuman’ pertama digunakan untuk mencatat ’piring’ mana yang terakhir kali diisi oleh producer. ’Papan pengumuman’ kedua digunakan untuk mencatat ’piring’ mana yang terakhir kali diambil masakannya oleh consumer. Mengapa hal ini diperlukan? Karena proses producer dapat berhenti sebelum dia mengisi penuh semua ’piring’ yang ada. Sehingga ketika 6
0.5. PETUNJUK AKHIR
producer dijalankan lagi, dia tidak perlu mengisi dari ’piring’ pertama, dia harus melanjutkan mengisi ’piring’ berikutnya yang belum sempat diisi sebelum tadi dia berhenti di tengah jalan. Hal yang sama juga berlaku untuk consumer. Berdasarkan pemikiran seperti di atas, maka anda harus membuat shared memory yang berukuran (n + 2) byte dengan n = jumlah ’piring’ bertipe ’char’ Perhatikan bahwa tipe data untuk mencatat nomor ’piring’ tidak perlu bertipe integer, karena dalam tugas ini anda tidak diharuskan membuat buffer dengan jumlah besar. Jangan lebih dari 10. Jumlah ini cukup dicatat dengan tipe data char. Sekarang tinggal terserah keinginan anda, di bagian mana dari shared memory ’papan pengumuman’ ini akan diletakkan. Apakah di dua bagian pertama: +---------+---------+----------+-----+----------+ | papan-1 | papan-2 | piring-1 | ... | piring-n | +---------+---------+----------+-----+----------+ atau di dua bagian terakhir: +----------+-----+----------+---------+---------+ | piring-1 | ... | piring-n | papan-1 | papan-2 | +----------+-----+----------+---------+---------+ dan bagaimana anda mengatur agar lokasi byte yang tepat dibaca atau ditulis oleh consumer dan producer.
0.5
Petunjuk akhir
Untuk memudahkan dalam pengerjaan tugas, program yang anda buat (baik producer maupun consumer) ketika mulai dijalankan pertama kali harus mencoba untuk membuat semaphore dan shared memory. Jika semaphore dan shared memory dengan key yang disepakati belum ada, maka buatlah semaphore dan shared memory itu. Akan tetapi apabila semaphore dan shared memory sudah ada yang membuat, gunakan semaphore dan shared memory yang sudah ada itu. Gunakan template berikut ini untuk membuat shared memory: 7
0.5. PETUNJUK AKHIR
void createshm (int* shmid, char** segptr, key_t key) Selanjutnya program anda harus berperilaku sebagaimana mestinya, program producer harus selalu membuat item dan memasukkannya ke dalam shared memory. Untuk fungsi produce item() di producer, anda boleh membuat algoritma apa saja asalkan fungsi ini mengisi sebuah ’masakan char’ ke dalam ’piring-piring’ yang masih kosong. Bisa menggunakan algoritma acak (randomize() ), atau kalau merasa kesulitan, isi saja selalu dengan salah satu karakter (misalnya ’Z’).
8