簡體   English   中英

從shm_open()+ mmap()更改共享內存的可見性

[英]Visibility of change to shared memory from shm_open() + mmap()

假設我在CentOS 7 x86_64 + GCC 7上。

我想在共享內存中創建一個ringbuffer。

如果我有兩個進程Producer和Consumer,並且兩者共享一個命名的共享內存,它通過shm_open()+ mmap()創建/訪問。

如果制作人寫了類似的東西:

struct Data {
uint64_t length;
char data[100];
}

隨機時間到共享內存,消費者不斷輪詢共享內存進行讀取。 我是否會遇到某種同步問題,即成員長度可見,但成員數據仍處於編寫過程中? 如果是,那么避免這個問題的最有效技術是什么?

我看到這篇文章: 共享內存IPC同步(無鎖)

但我希望能夠更深入,更低級地了解在兩個流程之間有效同步所需的內容。

提前致謝!

為避免這種情況,您可能希望使結構std::atomic並使用acquire-release內存排序訪問它。 在大多數現代處理器上,插入的指令是內存屏障,它保證編寫器在開始寫入之前等待所有負載完成,並且讀取器在開始讀取之前等待所有存儲完成。

此外,還有POSIX中的鎖定原語,但<atomic>標題更新,你可能想要的。

標准說的是什么

來自[atomics.lockfree],重點補充說:

無鎖的操作也應該是無地址的。 也就是說,通過兩個不同地址在同一存儲器位置上的原子操作將以原子方式進行通信。 實現不應該依賴於任何每個進程的狀態。 此限制允許通過多次映射到進程的內存以及在兩個進程之間共享的內存進行通信。

對於可鎖定的原子,標准在[thread.rec.lockable.general]中說,重點是:

執行代理是諸如可以與其他執行代理並行執行工作的線程之類的實體。 [...]實施或用戶可能會引入其他類型的代理, 例如流程 [....]

您有時會看到聲稱該標准沒有提及使用<atomic>原語與進程之間共享的內存,只有線程。 這是不正確的。

但是,通過共享內存將指針傳遞給另一個進程將無法工作,因為共享內存可能會映射到地址空間的不同部分,當然,指向不在共享內存中的任何對象的指針也是正確的。 共享內存中對象的索引和偏移量。 (或者,如果你真的需要指針,Boost提供IPC安全包裝器。)

是的,您最終會遇到數據爭用,不僅是在寫入data之前寫入和讀取的length ,而且這些成員的一部分將與您的進程讀取不同步。

雖然無鎖是一種新趨勢,但我建議你選擇一個更簡單的工具作為你的第一個IPC同步工作:信號量。 在linux上,以下手冊頁將非常有用:

這個想法是讓兩個進程發信號通知它正在讀取或編寫共享內存段的另一個進程。 使用信號量,您可以編寫進程間互斥:

Producer:
while true:
    (opt) create resource
    lock semaphore (sem_wait)
    copy resource to shm
    unlock semaphore (sem_post)

Consumer:
while true:
    lock semaphore (sem_wait)
    copy resource to local memory
        or crunch resource
    unlock semaphore (sem_post)

如果例如Producer寫入shm而Consumer調用sem_wait ,則Consumer將阻塞,直到Producer將調用sem_post但是 ,你無法保證 Producer不會再去另一個循環,連續兩次寫入消費者將被喚醒。 你必須建立一個不確定生產者和消費者的機制。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM