共享記憶體的資料同步

2021-07-22 22:53:27 字數 2042 閱讀 7506

在後台開發中,經常需要在多程序間進行資料共享,共享記憶體是乙個較常見的選擇。其他的ipc方式,包括磁碟檔案、訊號、套接字、管道、訊息佇列等,在需要傳輸大量資料時,效能都遜於共享記憶體。

共享記憶體是一段可以被多程序共享的物理記憶體,各個程序在使用之前,需要將這段物理記憶體對映到本程序的虛擬位址空間,系統呼叫是shmget+shmat或者shm_open+mmap。需要注意的是,各程序內的虛擬位址空間可能不一樣,並且程序a修改共享記憶體的內容後,程序b可以立即讀取。

多個程序同時讀寫共享記憶體時,由於讀寫順序不能保證,可能會導致資料錯亂。因此需要引入同步機制,保證讀寫操作以一定的順序執行。本節將介紹幾種實現同步的方式。

首先想到的就是鎖了。作業系統為我們提供了多種型別的鎖,諸如互斥鎖、讀寫鎖、自旋鎖等。互斥鎖(pthread_mutex_t)可以保證執行緒間的互斥鎖,通過設定互斥鎖的程序間共享屬性,可以實現程序間共用互斥鎖。相應地,我們可以將讀寫鎖、自旋鎖改造為多程序共享的。這種方式有乙個隱患:當加鎖程序異常退出時,其他程序可能永遠無法搶到鎖。程序間共享的互斥鎖示例**如下:

// 建立乙個程序間共享的互斥鎖

// shm_ptr是共享記憶體對映得來的虛擬位址

intcreate_process_mutex

(void

*shm_ptr

,pthread_mutex_t

*&mutex)

其次,訊號量也是乙個常見的多程序同步方式。通過semget或者sem_open開啟乙個訊號量,然後通過pv操作來達到程序間互斥的效果。但是訊號量也存在加鎖程序異常退出時,不能自動解鎖的問題。

第三,檔案記錄鎖可以鎖定檔案的一部分或者全部。假設我們將檔案與共享記憶體中的資料塊對應起來,則可以通過檔案鎖來同步共享記憶體的讀寫操作。值得說明的時,當程序異常退出時,該程序持有的檔案鎖會自動釋放。相對於訊號量,檔案鎖的效率稍差。示例**如下:

intop_flock

(int

fid,

intcmd

,size_t offset

,size_t length)

// 加檔案鎖

intlock_flock

(int

fid,

size_t offset

,size_t length)

// 解檔案鎖

intunlock_flock

(int

fid,

size_t offset

,size_t length)

最後,如果對共享記憶體的操作都足夠快,則可以模擬自旋鎖的過程,實現同步。自旋鎖在搶不到鎖時進入自旋等待,直至別的程序\執行緒釋放鎖。我們可以通過原子操作來實現這個過程,從4.1.2開始,gcc提供了一系列原子操作操作,實現自旋鎖需要cas和set。示例**如下:

// 山寨自旋鎖:加鎖

void

water_spin_lock

(void

*shm_ptr);

nanosleep

(&ts,&

ts);

// 自旋會霸佔cpu,稍息}}

///< while

}// 山寨自旋鎖:解鎖

void

water_spin_unlock

(void

*shm_ptr)

上一節給出了幾種共享記憶體間同步資料的通用方法,實際上,如果能使用無鎖資料結構,則可以避免同步操作,直達目標。比如我們經常用到的生產者-消費者模型中的佇列,可以使用無鎖佇列來實現。

假設只儲存最近一分鐘的計數。在共享記憶體中開闢60*8b的空間,即60個uint64_t,其中每個元素的高32-bit為秒級時間戳,低32-bit表示該時間戳內的計數。使用cas操作,可以保證多程序安全的操作這塊共享記憶體。核心**如下:

// 增加計數器

void

addcount

(void

*shm_ptr

,uint32_t steps =1

)///< for

}  

共享記憶體作為交換資料效率較高的ipc方式,在後台開發中經常被使用。我們可以通過多種方式來實現資料同步,包括共享執行緒鎖、檔案鎖、使用無鎖結構。

共享記憶體 同步 互斥

共享記憶體沒有提供互斥機制,需要程式設計師自己實現。1.對於多個程序共享的共享記憶體來說,惟一可靠的互斥機制 就是帶sem undo的system v訊號量。原因 某乙個程序在持有鎖期間意外退出,所持有的鎖還沒有來得及釋放,這回造成 所有等待 p操作 這個鎖的程序 執行緒死鎖。所以不建議使用posi...

資料共享,記憶體對映檔案和虛擬記憶體,共享記憶體

記憶體對映檔案允許開發人員預定一塊位址空間區域並給區域調撥物理儲存器。記憶體對映檔案的物理儲存器來自磁碟已有的檔案,而不是來自系統的頁交換檔案。一旦把檔案對映到位址空間,就可以對它進行訪問,就好像整個檔案都已經被載入記憶體一樣。不必再對檔案執行i o操作。使用記憶體對映檔案來顛倒檔案內容時,先開啟檔...

jvm堆記憶體的資料共享

以前沒學jvm的時候,老師總是講在堆記憶體中的資料是共享的,多個執行緒可以使用堆中的同乙個資料,於是才會有加鎖的操作。其實,堆裡的資料就是是共享的 那麼tlab是怎麼一回事呢?首先物件分配時,現在當前執行緒中的tlab中檢視空間是否有多餘,如果有,則分配到此執行緒中的tlab中。1.tlab是在堆記...