Ⅰ 如何設置linux的共享內存
我們可以修改shmmax內核參數,使SGA存在於一個共享內存段中。
通過修改/proc/sys/kernel/shmmax參數可以達到此目的。
[root@neirong root]# echo 1073741824 > /proc/sys/kernel/shmmax
[root@neirong root]# more /proc/sys/kernel/shmmax
1073741824這里設為1G。
對於shmmax文件的修改,系統重新啟動後會復位。可以通過修改 /etc/sysctl.conf 使更改永久化。
在該文件內添加以下一行 kernel.shmmax = 1073741824 這個更改在系統重新啟動後生效.
1、設置 SHMMAX
SHMMAX
參數定義共享內存段的最大尺寸(以位元組為單位)。在設置 SHMMAX 時,切記 SGA 的大小應該適合於一個共享內存段。 SHMMAX 設置不足可能會導致以下問題:
ORA-27123:unable to attach to shared memory segment
您可以通過執行以下命令來確定 SHMMAX 的值:
# cat /proc/sys/kernel/shmmax
33554432
SHMMAX 的默認值是 32MB 。我一般使用下列方法之一種將 SHMMAX 參數設為 2GB :
通過直接更改 /proc 文件系統,你不需重新啟動機器就可以改變 SHMMAX 的默認設置。我使用的方法是將以下命令放入 /etc/rc.local 啟動文件中:
# >echo "2147483648" > /proc/sys/kernel/shmmax
您還可以使用 sysctl 命令來更改 SHMMAX 的值:
# sysctl -w kernel.shmmax=2147483648
最後,通過將該內核參數插入到 /etc/sysctl.conf 啟動文件中,您可以使這種更改永久有效:
# echo "kernel.shmmax=2147483648" >> /etc/sysctl.conf
2、設置 SHMMNI
我們現在來看 SHMMNI 參數。這個內核參數用於設置系統范圍內共享內存段的最大數量。該參數的默認值是 4096 。這一數值已經足夠,通常不需要更改。
您可以通過執行以下命令來確定 SHMMNI 的值:
# cat /proc/sys/kernel/shmmni
4096
3、設置 SHMALL
最後,我們來看 SHMALL 共享內存內核參數。該參數控制著系統一次可以使用的共享內存總量(以頁為單位)。簡言之,該參數的值始終應該至少為:
ceil(SHMMAX/PAGE_SIZE)
SHMALL 的默認大小為 2097152 ,可以使用以下命令進行查詢:
# cat /proc/sys/kernel/shmall
2097152
SHMALL 的默認設置對於我們的 Oracle9 i RAC 安裝來說應該足夠使用。
注意: 在 i386 平台上 Red Hat Linux 的 頁面大小 為 4096 位元組。但是,您可以使用 bigpages ,它支持配置更大的內存頁面尺寸。
Ⅱ linux 共享內存 可不可以不加鎖呢 系統有兩個進程,一個負責寫入,一個負責讀取
Linux共享內存可以不用加鎖,不過需要一種機制來標記共享內存的讀寫狀態;
也就是說要讓兩個進程知道:
1)負責寫入的進程,必須知道當前共享內存是否可以寫入,上一次的寫入內容是否有被負責讀取的進程讀走;
2)負責讀取的進程,必須知道當前共享內存是否需要讀取,防止重復讀取。
一般的這種標記機制是通過以下方式來簡單實現:
1)通過讀寫鎖來控制;
2)共享內存上設置一個地方,專門存放當前共享內存的讀寫狀態;
Ⅲ Linux進程間通信(互斥鎖、條件變數、讀寫鎖、文件鎖、信號燈)
為了能夠有效的控制多個進程之間的溝通過程,保證溝通過程的有序和和諧,OS必須提供一定的同步機制保證進程之間不會自說自話而是有效的協同工作。比如在 共享內存的通信方式中,兩個或者多個進程都要對共享的內存進行數據寫入,那麼怎麼才能保證一個進程在寫入的過程中不被其它的進程打斷,保證數據的完整性 呢?又怎麼保證讀取進程在讀取數據的過程中數據不會變動,保證讀取出的數據是完整有效的呢?
常用的同步方式有: 互斥鎖、條件變數、讀寫鎖、記錄鎖(文件鎖)和信號燈.
互斥鎖:
顧名思義,鎖是用來鎖住某種東西的,鎖住之後只有有鑰匙的人才能對鎖住的東西擁有控制權(把鎖砸了,把東西偷走的小偷不在我們的討論范圍了)。所謂互斥, 從字面上理解就是互相排斥。因此互斥鎖從字面上理解就是一點進程擁有了這個鎖,它將排斥其它所有的進程訪問被鎖住的東西,其它的進程如果需要鎖就只能等待,等待擁有鎖的進程把鎖打開後才能繼續運行。 在實現中,鎖並不是與某個具體的變數進行關聯,它本身是一個獨立的對象。進(線)程在有需要的時候獲得此對象,用完不需要時就釋放掉。
互斥鎖的主要特點是互斥鎖的釋放必須由上鎖的進(線)程釋放,如果擁有鎖的進(線)程不釋放,那麼其它的進(線)程永遠也沒有機會獲得所需要的互斥鎖。
互斥鎖主要用於線程之間的同步。
條件變數:
上文中提到,對於互斥鎖而言,如果擁有鎖的進(線)程不釋放鎖,其它進(線)程永遠沒機會獲得鎖,也就永遠沒有機會繼續執行後續的邏輯。在實際環境下,一 個線程A需要改變一個共享變數X的值,為了保證在修改的過程中X不會被其它的線程修改,線程A必須首先獲得對X的鎖。現在假如A已經獲得鎖了,由於業務邏 輯的需要,只有當X的值小於0時,線程A才能執行後續的邏輯,於是線程A必須把互斥鎖釋放掉,然後繼續「忙等」。如下面的偽代碼所示:
1.// get x lock
2.while(x
Ⅳ 探討一下 Linux 共享內存的 N 種方式
關於 Linux 共享內存,寫得最好的應該是宋寶華的 《世上最好的共享內存》 一文。
本文可以說是對這篇文章的學習筆記,順手練習了一下 rust libc —— shichaoyuan/learn_rust/linux-shmipc-demo
按照宋寶華的總結,當前有四種主流的共享內存方式:
前兩種方式比較符合傳統的用法,共享內存做為進程間通信的媒介。
第三種方式更像是通過傳遞內存「句柄」進行數據傳輸。
第四種方式是為設備間傳遞數據設計,避免內存拷貝,直接傳遞內存「句柄」。
這里嘗試了一下第二種和第三種方式。
這套 API 應該是最普遍的 —— shm_open + mmap,本質上來說 Aeron 也是用的這種方式(關於 Aeron 可以參考 我之前的文章 )。
看一下 glibc 中 shm_open 函數的實現就一清二楚了:
shm_open 函數就是在 /dev/shm 目錄下建文件,該目錄掛載為 tmpfs,至於 tmpfs 可以簡單理解為存儲介質是內存的一種文件系統,更准確的理解可以參考官方文檔 tmpfs.txt 。
然後通過 mmap 函數將 tmpfs 文件映射到用戶空間就可以隨意操作了。
優點:
這種方式最大的優勢在於共享的內存是有「實體」(也就是 tmpfs 中的文件)的,所以多個進程可以很容易通過文件名這個信息構建共享內存結構,特別適合把共享內存做為通信媒介的場景(例如 Aeron )。
缺點:
如果非要找一個缺點的話,可能是,文件本身獨立於進程的生命周期,在使用完畢後需要注意刪除文件(僅僅 close 是不行的),否則會一直佔用內存資源。
memfd_create 函數的作用是創建一個匿名的文件,返回對應的 fd,這個文件當然不普通,它存活在內存中。更准確的理解可以參考官方文檔 memfd_create(2) 。
直觀理解,memfd_create 與 shm_open 的作用是一樣的,都是創建共享內存實體,只是 memfd_create 創建的實體是匿名的,這就帶了一個問題:如何讓其它進程獲取到匿名的實體?shm_open 方式有具體的文件名,所以可以通過打開文件的方式獲取,那麼對於匿名的文件怎麼處理呢?
答案是:通過 Unix Domain Socket 傳遞 fd。
rust 的 UDS 實現:
rust 在 std 中已經提供了 UDS 的實現,但是關於傳遞 fd 的 send_vectored_with_ancillary 函數還屬於 nightly-only experimental API 階段。所以這里使用了一個三方 crate —— sendfd ,坦白說可以自己實現一下,使用 libc 構建好 SCM_RIGHTS 數據,sendmsg 出去即可,不過細節還是挺多,我這里就放棄了。
這套 API 設計更靈活,直接拓展了我的思路,本來還是受限於 Aeron 的用法,如果在這套 API 的加持下,是否可以通過傳遞數據包內存塊(fd)真正實現零拷貝呢?
優點:
靈活。
缺點:
無
Ⅳ linux兩種共享內存的區別
持久性不同、文件反射方式不同。
1、持久性不同。sysvshm是持久化的,除非被一個進程明確的刪除,否則它始終存在於內存里,直到系統關機。mmap映射的內存在不是持久化的,假如進程關閉,映射隨即失效,除非事前已經映射到了一個文件上。
2、文件反射方式不同。前者用COW的方式,把文件映射到當前的進程空間,修改操作不會改動源文件。後者直接把文件映射到當前的進程空間,所有的修改會直接反應到文件的page cache,而後由內核自動同步到映射文件上。
Ⅵ linux共享鎖與排斥鎖的作用
共享鎖【S鎖】又稱讀鎖,若事務T對數據對象A加上S鎖,則事務T可以讀A但不能修改A,其他事務只能再對A加S鎖,而不能加X鎖,直到T釋放A上的S鎖。這保證了其他事務可以讀A,但在T釋放A上的S鎖之前不能對A做任何修改。排他鎖【X鎖】又稱寫鎖。若事務T對數據對象A加上X鎖,事務T可以讀A也可以修改A,其他事務不能再對A加任何鎖,直到T釋放A上的鎖。這保證了其他事務在T釋放A上的鎖之前不能再讀取和修改A。
Ⅶ linux查看共享內存命令
共享內存查看
使用ipcs命令,不加如何參數時,會把共享內存、信號量、消息隊列的信息都列印出來,如果只想顯示共享內存信息,使用如下命令:
[root@localhost ~]# ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 1867776 root 600 393216 2 dest
0x00000000 1900545 root 600 393216 2 dest
0x00030021 1703938 zc 666 131104 1
0x0003802e 1736707 zc 666 131104 1
0x00030004 1769476 zc 666 131104 1
0x00038002 1802245 zc 666 131104 1
0x00000000 1933318 root 600 393216 2 dest
0x00000000 1966087 root 600 393216 2 dest
0x00000000 1998856 root 600 393216 2 dest
0x00000000 2031625 root 600 393216 2 dest
0x00000000 2064394 root 600 393216 2 dest
0x0014350c 2261003 cs 666 33554432 2
0x00000000 2129932 root 600 393216 2 dest
0x00000000 2162701 root 600 393216 2 dest
0x00143511 395837454 root 666 1048576 1
其中:
第一列就是共享內存的key;
第二列是共享內存的編號shmid;
第三列就是創建的用戶owner;
第四列就是許可權perms;
第五列為創建的大小bytes;
第六列為連接到共享內存的進程數nattach;
第七列是共享內存的狀態status。其中顯示「dest」表示共享內存段已經被刪除,但是還有用戶在使用它,當該段內存的mode欄位設置為SHM_DEST時就會顯示「dest」。當用戶調用shmctl的IPC_RMID時,內存先查看多少個進程與這個內存關聯著,如果關聯數為0,就會銷毀這段共享內存,否者設置這段內存的mod的mode位為SHM_DEST,如果所有進程都不用則刪除這段共享內存。
Ⅷ Linux進程通信實驗(共享內存通信,接上篇)
這一篇記錄一下共享內存實驗,需要linux的共享內存機制有一定的了解,同時也需要了解POSIX信號量來實現進程間的同步。可以參考以下兩篇博客: https://blog.csdn.net/sicofield/article/details/10897091
https://blog.csdn.net/ljianhui/article/details/10253345
實驗要求:編寫sender和receiver程序,sender創建一個共享內存並等待用戶輸入,然後把輸入通過共享內存發送給receiver並等待,receiver收到後把消息顯示在屏幕上並用同樣方式向sender發送一個over,然後兩個程序結束運行。
這個實驗的難點主要在於共享內存的創建和撤銷(涉及到的步驟比較多,需要理解各步驟的功能),以及實現兩個進程間的相互等待(使用信號量來實現,這里使用了有名信號量)
實驗心得:學習理解了linux的共享內存機制以及POSIX信號量機制。
兩個實驗雖然加強了對linux一些機制的理解,但是感覺對linux的學習還不夠,需要繼續學習。
Ⅸ 共享內存原理
Linux的2.2.x內核支持多種共享內存方式,如mmap()系統調用,Posix共享內存,以及系統V共享內存。
共享內存可以說是最有用的進程間通信方式,也是最快的IPC形式。兩個不同進程A、B共享內存的意思是,同一塊物理內存被映射到進程A、B各自的進程地址空間。進程A可以即時看到進程B對共享內存中數據的更新,反之亦然。由於多個進程共享同一塊內存區域,必然需要某種同步機制,互斥鎖和信號量都可以。
系統V共享內存原理
進程間需要共享的數據被放在一個叫做IPC共享內存區域的地方,所有需要訪問該共享區域的進程都要把該共享區域映射到本進程的地址空間中去。系統V共享內存通過shmget獲得或創建一個IPC共享內存區域,並返回相應的標識符。內核在保證shmget獲得或創建一個共享內存區,初始化該共享內存區相應的shmid_kernel結構注同時,還將在特殊文件系統shm中,創建並打開一個同名文件,並在內存中建立起該文件的相應dentry及inode結構,新打開的文件不屬於任何一個進程(任何進程都可以訪問該共享內存區)。所有這一切都是系統調用shmget完成的。
Linux 有一個系統調用叫 mmap(),這個 mmap() 可以把一個文件映射到進程的地址空間(進程使用的虛擬內存),這樣進程就可以通過讀寫這個進程地址空間來讀寫這個文件。
你可能會覺得奇怪,我明明寫的是內存啊,怎麼會變成寫文件了呢?他們之間是怎麼轉化的呢?
沒錯,你寫的確實是內存,但是你寫的這個內存不是普通的內存,你寫在這個內存上的內容,過段時間後會被內核寫到這個文件上面。而寫文件,其實最後都會變成寫數據到設備里(硬碟、Nand Flash 等)。
mmap的優點主要在為用戶程序隨機的訪問,操作,文件提供了一個方便的操作方法;其次就是為不同進程共享大批量數據提供高效的手段;另外就是對特大文件(無法一次性讀入內存)的處理提供了一種有效的方法。
內核里存在著一個特殊的文件系統,這個文件系統的存儲介質不是別的,正是 RAM。
在 shmget() 調用之後,系統會為你在這個文件系統上創建一個文件,但是這個時候僅僅是創建了這個文件。
然後你就應該調用 shmat() 了,調用 shmat() 之後,內核會使用 mmap 把這個文件映射到你的進程地址空間,這個時候你就能直接讀寫映射後的地址了。
過段時間,內核把你寫的 內容寫到了文件裡面,但是,這個文件的存儲介質是內存,所以他會怎麼做?看明白了吧?
答案:他會寫入內存呀
我們先來看看如果不使用內存映射文件的處理流程是怎樣的,首先我們得先讀出磁碟文件的內容到內存中,然後修改,最後回寫到磁碟上。第一步讀磁碟文件是要經過一次系統調用的,它首先將文件內容從磁碟拷貝到內核空間的一個緩沖區,然後再將這些數據拷貝到用戶空間,實際上是兩次數據拷貝。第三步回寫也一樣也要經過兩次數據拷貝。
所以我們基本上會有四次數據的拷貝了,因為大文件數據量很大,幾十GB甚至更大,所以拷貝的開銷是非常大的。
而內存映射文件是操作系統的提供的一種機制,可以減少這種不必要的數據拷貝,從而提高效率。它由mmap()將文件直接映射到用戶空間,mmap()並沒有進行數據拷貝,真正的數據拷貝是在缺頁中斷處理時進行的,由於mmap()將文件直接映射到用戶空間,所以中斷處理函數根據這個映射關系,直接將文件從硬碟拷貝到用戶空間,所以只進行了一次數據拷貝 ,比read進行兩次數據拷貝要好上一倍,因此,內存映射的效率要比read/write效率高。
一般來說,read write操作可以滿足大多數文件操作的要求,但是對於某些特殊應用領域所需要的幾十GB甚至更大的存儲,這種通常的文件處理方法進行處理顯然是行不通的。
mmap將一個文件或者其它對象映射進內存。文件被映射到多個頁上,如果文件的大小不是所有頁的大小之和,最後一個頁不被使用的空間將會清零。munmap執行相反的操作,刪除特定地址區域的對象映射。
當使用mmap映射文件到進程後,就可以直接操作這段虛擬地址進行文件的讀寫等操作,不必再調用read,write等系統調用.但需注意,直接對該段內存寫時不會寫入超過當前文件大小的內容.
參考地址:
Ⅹ linux|進程間通信如何加鎖
進程間通信有一種[共享內存]方式,大家有沒有想過,這種通信方式中如何解決數據競爭問題?我們可能自然而然的就會想到用鎖。但我們平時使用的鎖都是用於解決線程間數據競爭問題,貌似沒有看到過它用在進程中,那怎麼辦?
關於進程間的通信方式估計大多數人都知道,這也是常見的面試八股文之一。
個人認為這種面試題沒什麼意義,無非就是答幾個關鍵詞而已,更深入的可能面試官和面試者都不太了解。
關於進程間通信方式我之前在【這篇文章】中有過介紹,感興趣的可以移步去看哈。
進程間通信有一種[共享內存]方式,大家有沒有想過,這種通信方式中如何解決數據競爭問題?
我們可能自然而然的就會想到用鎖。但我們平時使用的鎖都是用於解決線程間數據競爭問題,貌似沒有看到過它用在進程中,那怎麼辦?
我找到了兩種方法,信號量和互斥鎖。
直接給大家貼代碼吧,首先是信號量方式:
代碼中的MEOW_DEFER,它內部的函數會在生命周期結束後觸發。它的核心函數其實就是下面這四個:
具體含義大家應該看名字就知道,這里的重點就是sem_init中的pshared參數,該參數為1表示可在進程間共享,為0表示只在進程內部共享。
第二種方式是使用鎖,即pthread_mutex_t,可是pthread_mutex不是用作線程間數據競爭的嗎,怎麼能用在進程間呢?
可以給它配置一個屬性,示例代碼如下:
它的默認屬性是進程內私有,但是如果給它配置成PTHREAD_PROCESS_SHARED,它就可以用在進程間通信中。
相關視頻推薦
360度無死角講解進程管理,調度器的5種實現
Linux進程間通信-信號量、消息隊列和共享內存
學習地址:C/C++Linux伺服器開發/後台架構師【零聲教育】-學習視頻教程-騰訊課堂
需要C/C++ Linux伺服器架構師學習資料加qun812855908獲取(資料包括 C/C++,Linux,golang技術,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒體,CDN,P2P,K8S,Docker,TCP/IP,協程,DPDK,ffmpeg 等),免費分享
完整代碼如下:
我想這兩種方式應該可以滿足我們日常開發過程中的大多數需求。
鎖的方式介紹完之後,可能很多朋友自然就會想到原子變數,這塊我也搜索了一下。但是也不太確定C++標准中的atomic是否在進程間通信中有作用,不過看樣子boost中的atomic是可以用在進程間通信中的。
其實在研究這個問題的過程中,還找到了一些很多解決辦法,包括:
Disabling Interrupts
Lock Variables
Strict Alternation
Peterson's Solution
The TSL Instruction
Sleep and Wakeup
Semaphores
Mutexes
Monitors
Message Passing
Barriers
這里就不過多介紹啦,大家感興趣的可以自行查閱資料哈。