Bagaimana cara membagi memori antara aplikasi yang ditulis dalam C / C ++

10

Saya akan melalui program yang ditulis dalam C / C ++ untuk kontrol dalam robotika. Pada dasarnya, tiga program berbeda berjalan secara bersamaan, dan mereka berkomunikasi melalui memori bersama. Google-ling sekitar saya menemukan berpikir seperti vxWorks dan meningkatkan header interprocess perpustakaan ( Meningkatkan dokumentasi: Berbagi memori antara proses ).

Sekarang, saya tidak ingin melihat implementasinya, saya bisa membaca tautan di atas. Tapi saya tidak bisa mendapatkan kepala saya sekitar bagaimana perpustakaan meningkatkan melakukan ini. Maksud saya, satu aplikasi mengalokasikan memori, dan lainnya mengakses memori itu, tetapi bagaimana mereka berkomunikasi? bukankah tidak aman untuk melakukan ini?

cauchy
sumber
apa yang tampak tidak jelas dalam dokumen yang Anda referensikan? "Ketika menempatkan objek di wilayah yang dipetakan dan memetakan wilayah itu di alamat berbeda di setiap proses, pointer mentah adalah masalah karena mereka hanya valid untuk proses yang menempatkan mereka di sana. Untuk menyelesaikan ini, Boost.Interprocess menawarkan penunjuk pintar khusus yang dapat digunakan sebagai pengganti pointer mentah. Jadi kelas pengguna yang mengandung pointer mentah (atau Meningkatkan pointer pintar, yang secara internal memiliki pointer mentah) tidak dapat dengan aman ditempatkan dalam proses yang dipetakan bersama wilayah. Petunjuk ini harus diganti dengan ... "
nyamuk
Jangan lupa sistem operasi adalah proses yang benar-benar menjaga memori. Proses yang mengalokasikan dan menggunakan memori pada akhir hari menggunakan OS untuk membuat permintaan mereka. OS mengelola multi-pemrosesan dan memastikan tidak akan ada konflik.
Rob Sedgwick
@gnat Implementasinya jelas. Bagaimana Boost membuat implementasi itu bukan pada dokumen-dokumen itu ... Saya tidak ingin mengulanginya (itu tidak masuk akal) tetapi untuk memahaminya.
cauchy

Jawaban:

12

Tapi saya tidak bisa mendapatkan kepala saya sekitar bagaimana perpustakaan meningkatkan melakukan ini.

Mekanisme antar proses boost memiliki tiga komponen yang diperlukan untuk bekerja:

  1. file yang dipetakan memori: file yang dipetakan memori perlu dibuat dan diteruskan ke pengalokasi proses boost.inter. Pengalokasi ini akan mengambil potongan file dan menggunakannya seolah-olah dikembalikan oleh std :: pengalokasi, dengan pemetaan diterapkan sehingga memori kompatibel dengan memori spesifik yang sedang diproses.

  2. boost.interprocess container; wadah jenis ini akan menggunakan memori yang dikembalikan oleh pengalokasi dan menawarkan antarmuka std :: container like (begin / end / size / push_back, dll).

  3. mekanisme sinkronisasi; ini bisa berupa mutasi antarproses dan harus digunakan untuk mencegah kondisi ras akses data.

Maksud saya, satu aplikasi mengalokasikan memori, dan lainnya mengakses memori itu, tetapi bagaimana mereka berkomunikasi? bukankah tidak aman untuk melakukan ini?

Memori yang dialokasikan sebenarnya adalah file yang dipetakan dengan memori bersama. Komunikasi tidak langsung, dengan kedua aplikasi mengatur atau membaca data, sesuai kebutuhan. Keamanan berasal dari penggunaan primitif sinkronisasi antarproses.

utnapistim
sumber
2
Perlu dicatat: Ketiga mekanisme IPC ini membutuhkan dukungan kernel, jadi bagi mereka yang ingin tahu bagaimana hal ini dilakukan (seperti yang ditunjukkan OP), itu tidak bisa hanya dilakukan oleh aplikasi individual. Aplikasi harus meminta kernel ke memori memetakan file atau menyinkronkan dengan proses lain.
Cort Ammon
5

memori bersama bukanlah gambaran lengkap untuk IPC, ini merupakan mekanisme penyampaian data tetapi Anda masih perlu beberapa cara untuk memberi tahu proses lain bahwa beberapa data telah diperbarui dan tersedia untuk dibaca. Bagaimana Anda melakukan ini terserah Anda, biasanya Anda akan menggunakan mutex OS atau objek acara, setiap proses menunggu ini untuk ditetapkan, penulisan aplikasi menetapkannya setelah penulisan selesai. Kemudian utas di program lain bangun dan membaca.

Atau Anda dapat melakukan polling, membaca data secara teratur untuk nilai yang berubah ketika data diperbarui (misalnya penghitung yang bertambah).

gbjbaanb
sumber
4

Boost menggunakan pemetaan memori suatu file.

Unix dan windows mendukung pembuatan file yang tidak ada pada sistem file normal hanya untuk tujuan ini.

Maka Anda perlu menyinkronkan akses ke memori itu seperti yang Anda lakukan jika ada utas yang mengaksesnya. Berarti membaca bersamaan dapat terjadi tanpa sinkronisasi tetapi begitu satu proses ingin menulis Anda harus mencegah yang lain mengaksesnya.

Pengoperasian atom pada memori bersama masih dimungkinkan jika Anda ingin sinkronisasi tanpa kunci.

aneh ratchet
sumber
Bisakah Anda menguraikan "Operasi atom pada memori bersama masih dimungkinkan jika Anda ingin sinkronisasi tanpa kunci"? Anda bermaksud mengatakan bahwa jika setiap program adalah C ++ Anda harus menggunakan std::atomickelas template C ++ 11 ( cplusplus.com/reference/atomic ) di masing-masing dari dua program agar mereka dapat menulis ke ruang bersama tanpa sinkronisasi yang dipaksakan melalui kunci?
Gabriel Staples
@GabrielStaples yeah atau intrinsik atom setara
ratchet freak
Maaf mengganggumu lagi; Saya tidak terbiasa dengan "intrinsik atom." Bisakah Anda mengarahkan saya ke referensi untuk mempelajarinya lebih lanjut? Pencarian google cepat tidak jelas.
Gabriel Staples
3

Memori bersama masih hanya memori. Anda dapat meletakkan mutex, spinlock, atau primitif sinkronisasi lainnya di sana, dan menggunakannya untuk menyinkronkan akses proses Anda ke memori bersama, persis seperti utas menggunakan primitif itu untuk menyinkronkan akses ke memori yang terlihat oleh mereka.

Satu-satunya perbedaan nyata adalah:

  1. utas berbagi semua memori dan ruang alamat yang sama, jadi pointer mentah berfungsi untuk mereka. Memori yang dibagikan antar proses bekerja persis sama, tetapi dapat dipetakan pada alamat yang berbeda di setiap proses, sehingga Anda tidak bisa dengan mudah melewati petunjuk mentah di antara mereka.

    • NB. ini memiliki efek knock-on pada beberapa detail implementasi metode virtual, informasi tipe runtime, dan beberapa mekanisme C ++ lainnya. Tetap gunakan jenis yang sepele yang dapat diinisialisasi (data lama biasa) tanpa metode virtual atau gips dinamis dalam memori bersama Anda, jangan gunakan typeid pada mereka, dan Anda harus baik-baik saja.
  2. beberapa primitif sinkronisasi mungkin memerlukan flag atau atribut khusus untuk bekerja dengan benar di antara proses (lihat PTHREAD_PROCESS_SHAREDatribut untuk mutex thread POSIX, misalnya). Ini tidak benar-benar berkaitan dengan memori dan sinkronisasi dalam diri mereka sendiri, tetapi karena interaksi kernel / scheduler diperlukan untuk membangunkan pelayan tidur.


Begitu:

tetapi bagaimana mereka berkomunikasi?

Dengan cara yang sama, berbagai utas berkomunikasi, memungkinkan untuk peringatan di atas

bukankah tidak aman untuk melakukan ini?

Ya, ini sama tidak amannya untuk proses berkomunikasi melalui memori bersama seperti halnya utas untuk berkomunikasi melalui memori bersama, dan mereka membutuhkan sinkronisasi yang setara (atau identik) untuk membuatnya aman.

Tak berguna
sumber
3

Perhatikan bahwa C dan C ++ adalah bahasa yang berbeda.

Memori bersama tidak mungkin dalam C11 murni standar , atau C ++ 11 (karena standar tidak mendefinisikan itu), atau bahkan C ++ 14 (yang n3690 draft, dan mungkin standar resmi, tidak menyebutkan memori bersama di luar multi-threading ). Jadi, Anda perlu perpustakaan tambahan untuk mendapatkan memori bersama. Tetapi beberapa sistem operasi memiliki dukungan untuk memori bersama. Jadi beberapa perpustakaan menyediakan memori bersama, dibangun di atas layanan sistem operasi yang ada, ada. Anda mungkin dapat mempertimbangkan untuk menggunakan perpustakaan kerangka POCO (yang abstrak atas rincian spesifik OS)

Untuk Linux (dan mungkin POSIX), lihat shm_overview (7) . Anda harus menyinkronkan, jadi lihat juga sem_overview (7)

VXWorks (yang saya tidak tahu, tetapi googled untuk itu) memiliki VxMP

Anda harus hati-hati memahami apa yang sebenarnya terjadi. Anda mungkin ingin berbagi hanya data lama struct-s (bukan kelas C ++!) Dan Anda harus sangat berhati-hati tentang alamat (setiap proses mungkin mendapatkan alamat yang berbeda untuk segmen memori bersama bersama) dan tentang sinkronisasi.

Atau, gunakan utas. Perhatikan bahwa standar C ++ 11 mendefinisikan pustaka thread .

Basile Starynkevitch
sumber
1
Tentu saja memori bersama itu dimungkinkan di C ++ 11 dan C11! kenyataannya itu bukan bagian dari standar tidak ada artinya, GUI juga bukan bagian dari standar. Ada beberapa perpustakaan beberapa lintas platform yang memungkinkan seseorang untuk menggunakan memori bersama dan berbagai metode sinkronisasi ...
AK_
1
Maksud
Saya pikir Anda harus meluangkan waktu untuk memahami apa arti istilah "standar bahasa" sebenarnya, apa implementasi standar yang sesuai, dan apa perpustakaan.
AK_
Tolong tunjukkan saya ke bagian dalam standar C ++ 11 (atau n3690 konsep C ++ 14) berbicara tentang memori bersama.
Basile Starynkevitch
3
Saya pikir kita berdua sepakat, tetapi kita mungkin tidak setuju tentang apa arti standar C ++ 11. Bagi saya, itu persis (tidak lebih dari) standar ISO C ++ 11 (atau konsep bebas yang setara dengannya). Pustaka eksternal tidak dihitung sebagai standar, bahkan jika pustaka itu umum dan lintas platform.
Basile Starynkevitch