Mapping MAP_SHARED yang writable memungkinkan proses mengubah state berbasis file dengan memory store biasa. Byte diakses melalui virtual memory, bukan dikirim lewat write(), tetapi mapping tersebut tetap berpartisipasi dalam state filesystem: perubahan dapat terlihat melalui shared mapping lain dan file I/O, lalu dirty page dapat ditulis kembali ke storage.
Antarmuka ini menyatukan beberapa mekanisme ke dalam satu rentang alamat. CPU store, page fault, residensi page cache, writeback filesystem, dan persistensi storage dapat terlibat dalam siklus hidup byte yang sama. Menyamakan store yang berhasil dengan output file yang sudah durable menghapus batas yang tetap dipisahkan oleh sistem operasi.
Mapping membentuk relasi, bukan salinan privat
Untuk regular file, mmap() mengaitkan interval virtual address dengan region file. Dengan MAP_SHARED, update pada mapping diteruskan ke file yang mendasarinya sesuai semantik mapping dan writeback platform. Ini berbeda dari MAP_PRIVATE, yang membuat modifikasi tetap privat bagi mapping dan tidak menjadikannya update file melalui mapping tersebut.
File offset yang diberikan ke mmap() harus memenuhi persyaratan alignment platform. Akses di dalam rentang mapping kemudian diterjemahkan melalui virtual-memory mapping. Sebuah page mungkin belum resident saat pertama kali disentuh; kernel dapat memicu fault, memuat page, dan membentuk page-table entry terkait sebelum instruksi selesai.
Batas pentingnya adalah aplikasi menerima alamat, bukan kepemilikan atas byte yang terlepas. Store seperti:
mapped[4096] = 0x7f;dapat membuat file-backed memory menjadi dirty. Tidak diperlukan pemanggilan write() untuk modifikasi tersebut. Ketiadaan write syscall di lokasi modifikasi tidak membuat operasi itu terpisah dari filesystem.
Visibilitas dan persistensi adalah properti terpisah
Shared mapping yang telah dimodifikasi dapat terlihat sebelum data berubah tersimpan secara durable. Di Linux, shared file mapping umumnya berinteraksi dengan page cache, sehingga mapped access dan buffered file I/O dapat merujuk ke data file cached yang sama. Koherensi tersebut merupakan properti sistem operasi, bukan aturan umum untuk setiap fasilitas mapping di semua platform.
Jika satu proses mengubah byte melalui writable shared mapping sementara proses lain membaca region file yang sama, proses kedua dapat melihat state cached yang telah berubah meski storage belum menyelesaikan writeback. Visibilitas bagi observer konkuren tidak membuktikan persistensi terhadap crash.
Pemisahan sebaliknya juga penting. Operasi persistensi memiliki scope dan prasyarat. msync() bekerja pada mapped page dalam suatu rentang alamat, sedangkan fsync() bekerja melalui file descriptor dan memiliki efek pada data serta metadata file sesuai semantik filesystem. Tidak satu pun API tersebut mengubah state aplikasi di sekitarnya menjadi satu transaksi atomik.
Setidaknya ada tiga state yang perlu dibedakan:
store issued
|
mapped state modified
|
change observable through coherent file state
|
dirty data written back
|
required storage persistence boundary completedTransisi persisnya bergantung pada sistem operasi, filesystem, hardware, flag, dan hasil error. Semua tahap itu bukan satu event yang tak terpisahkan.
msync mengendalikan rentang mapping
Di Linux, msync() meminta sinkronisasi page yang mencakup rentang mapped address tertentu. MS_SYNC meminta penyelesaian update secara sinkron; MS_ASYNC meminta penjadwalan secara asinkron. Alamat harus memenuhi page alignment yang diwajibkan, dan rentang harus merujuk pada mapped memory sesuai kontrak API.
Kontrak berbasis rentang ini penting. Sebuah proses dapat memetakan file besar tetapi hanya menyinkronkan sebagian:
if (msync(mapped + page_offset, page_len, MS_SYNC) == -1) {
/* handle synchronization failure */
}Kode ini valid hanya jika mapped + page_offset memenuhi aturan alignment platform dan rentangnya sesuai dengan mapping. Pemanggilan tersebut menyangkut mapped range, bukan setiap byte dari setiap file yang dapat dijangkau proses.
Linux memiliki perilaku implementasi yang dapat membuat sebagian penggunaan msync() tampak tidak diperlukan pada shared mapping biasa karena dirty mapped page dilacak untuk writeback dan page cache koheren dengan file I/O. Observasi itu tidak boleh diubah menjadi jaminan portabel pada level bahasa atau POSIX. Kode yang memerlukan batas sinkronisasi terdefinisi perlu menyatakan batas tersebut melalui API terdokumentasi dan menangani error.
Ukuran file tetap menjadi constraint eksternal
Mapping memiliki panjang virtual, sedangkan backing file memiliki ukurannya sendiri. Memetakan page pada umumnya tidak memperpanjang regular file hanya karena rentang virtual yang diminta lebih besar. Akses ke page yang seluruhnya berada di luar akhir file dapat memicu fault berbasis hardware yang dikirim ke proses, umumnya SIGBUS di Linux untuk kasus ini.
Kondisi tersebut membuat file truncation menjadi bahaya konkurensi. Sebuah proses dapat memegang mapping yang valid saat dibuat, sementara proses lain melakukan truncate pada file. Virtual mapping dapat tetap ada walaupun sebagian region backing file sudah tidak tersedia. Akses berikutnya ke page yang terdampak dapat gagal.
Race ini tidak selesai hanya dengan memeriksa ukuran file sebelum setiap akses. Aktor lain dapat melakukan truncate setelah pemeriksaan. Aplikasi yang mengizinkan resizing konkuren memerlukan kontrak sinkronisasi atau kepemilikan yang mencakup ukuran file sekaligus mapped access.
Memperbesar file juga memerlukan operasi ukuran file secara eksplisit seperti ftruncate() sebelum mengandalkan region baru sebagai backing. Mapping dan panjang logis file saling terkait, tetapi keduanya bukan objek yang sama.
Dirty mapped page adalah state resource
Memory mapping dapat membuat modifikasi file tampak seperti mutasi biasa di dalam proses, sehingga resource lifetime yang terlibat mudah tersembunyi. Dirty page memakai state yang dikelola kernel dan tunduk pada kebijakan writeback. Proses dapat terus berjalan sementara writeback berlangsung kemudian, dan writeback dapat menemui error yang belum ada saat CPU store semula terjadi.
Pemisahan waktu ini mengubah penanganan error. Assignment biasa tidak memiliki return value untuk kegagalan storage yang muncul kemudian. Software yang membutuhkan persistence boundary memerlukan operasi yang mampu melaporkan synchronization error serta keputusan eksplisit mengenai arti error tersebut bagi state machine di level lebih tinggi.
munmap() menghapus virtual mapping milik proses. Operasi ini tidak semestinya dipakai sebagai pengganti durability operation eksplisit ketika kontrak aplikasi membutuhkan persistensi tersinkronisasi. Demikian pula, process exit yang mengakhiri address-space lifetime bukan protokol durability yang memadai.
Mapping lifetime, dirty-page lifetime, dan storage lifetime saling tumpang tindih, tetapi tidak ada satu pun yang menjadi pengganti lengkap bagi yang lain.
Shared mapping tidak menciptakan transaksi level aplikasi
Dua field yang di-update melalui mapping yang sama tetap merupakan operasi memori terpisah kecuali ada mekanisme lebih kuat yang mengelompokkannya. Observer lain berpotensi melihat logical state campuran jika kontrak sinkronisasi aplikasi mengizinkan akses konkuren di antara kedua store.
Sebagai contoh:
record->payload = new_payload;
record->generation = new_generation;Urutan source-level tersebut tidak dengan sendirinya menyediakan update record atomik lintas thread, proses, crash, atau storage. Aturan compiler, CPU memory ordering, synchronization primitive, cache coherence, writeback filesystem, dan crash consistency berada pada lapisan yang terpisah.
Mutex yang dibagi antarproses dapat mengoordinasikan live access jika diinisialisasi dan digunakan dengan benar untuk interprocess synchronization. Mutex itu tidak otomatis membuat update multi-field menjadi crash-atomic. Format yang crash-consistent dapat memakai teknik seperti versioned record, copy-on-write structure, append record, checksum, atau commit marker eksplisit, masing-masing dengan persyaratan ordering dan persistensi sendiri.
Karena itu, mapped representation memerlukan ketelitian yang sama seperti format mutable bersama lainnya. Kemudahan addressing tidak menambahkan transactional semantics.
Akses konkuren memerlukan kontrak sinkronisasi memori
Saat beberapa thread atau proses mengakses mapped byte yang sama secara konkuren, file mapping menetapkan asal byte; mapping tidak menetapkan data-race semantics untuk bahasa pemrograman.
Dalam C dan C++, concurrent non-atomic access dapat dibatasi oleh language memory model ketika thread dalam satu program terlibat. Interprocess synchronization menambahkan persyaratan spesifik platform karena abstraksi bahasa tidak otomatis mencakup setiap process-shared primitive. Atomic type, process-shared mutex, protokol berbasis futex, atau mekanisme terdokumentasi lain dapat sesuai, bergantung pada representasi dan para partisipan.
File lock juga merupakan mekanisme berbeda. Advisory lock mengoordinasikan proses yang bekerja sama melalui konvensi locking, tetapi pada umumnya tidak mengubah arbitrary mapped load dan store menjadi operasi atomik pada level bahasa. Protokol lock harus dipatuhi setiap partisipan yang mengandalkannya.
Dengan demikian, batas antarmuka memiliki dua dimensi: mapping membentuk file-backed memory, sedangkan desain sinkronisasi terpisah membentuk mutasi konkuren yang aman.
Protokol persistensi perlu menetapkan batasnya
Desain file-backed mapping yang kuat menyatakan event yang dihitung sebagai publikasi dan event yang dihitung sebagai persistensi. Kedua event itu dapat berbeda.
Sebuah proses dapat memublikasikan versi in-memory baru kepada peer setelah meng-update mapped state dan melepas synchronization primitive. Setelah itu proses dapat menjalankan persistence operation sebelum mengakui durable commit kepada pemanggil eksternal. Desain lain dapat menyimpan update secara privat di tempat lain, menyalin image yang selesai ke shared mapping, menyinkronkan rentang terkait, lalu baru memajukan durable generation marker.
Setiap protokol memiliki failure window berbeda. Properti kritisnya adalah software tidak menyimpulkan durability dari visibility atau atomicity dari addressability.
MAP_SHARED kuat karena menghubungkan memory access dengan file-backed state tanpa banyak seremoni pada setiap load atau store. Hubungan yang sama menghilangkan syscall boundary yang biasanya menandai bahwa I/O sedang berlangsung. Desain yang tepat membentuk kembali batas yang hilang secara eksplisit: validitas mapped range, concurrency ownership, publication ordering, synchronization error, dan storage event yang diwajibkan oleh persistence contract aplikasi.