本文實例分析了Go語言共享內存讀寫的方法。分享給大家供大家參考。具體分析如下:
前面分析了Go語言指針運算和內嵌C代碼的方法,做了一個Go語言共享內存讀寫的實驗。
先大概說下什么是共享內存。我們知道不同進程見的內存是互相獨立的,沒辦法直接互相操作對方內的數據,而共享內存則是靠操作系統提供的內存映射機制,讓不同進程的一塊地址空間映射到同一個虛擬內存區(qū)域上,使不同的進程可以操作到一塊共用的內存塊。共享內存是效率最高的進程間通訊機制,因為數據不需要在內核和程序之間復制。
共享內存用到的是系統提供的mmap函數,它可以將一個文件映射到虛擬內存的一個區(qū)域中,程序使用指針引用這個區(qū)域,對這個內存區(qū)域的操作會被回寫到文件上,Go內置的syscall包中有mmap函數,但是它是經過封裝的,返回的是[]byte,沒辦法做我需求的指針運算,所以我還是用cgo來調用原生的mmap。
實驗分為讀和寫兩個程序,這樣我們可以觀察到讀進程可以讀到寫進程寫入共享內存的信息。
下面是shm_writer.go的代碼:
復制代碼 代碼如下:
package main
/*
#cgo linux LDFLAGS: -lrt
#include fcntl.h>
#include unistd.h>
#include sys/mman.h>
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
int my_shm_new(char *name) {
shm_unlink(name);
return shm_open(name, O_RDWR|O_CREAT|O_EXCL, FILE_MODE);
}
*/
import "C"
import (
"fmt"
"unsafe"
)
const SHM_NAME = "my_shm"
const SHM_SIZE = 4 * 1000 * 1000 * 1000
type MyData struct {
Col1 int
Col2 int
Col3 int
}
func main() {
fd, err := C.my_shm_new(C.CString(SHM_NAME))
if err != nil {
fmt.Println(err)
return
}
C.ftruncate(fd, SHM_SIZE)
ptr, err := C.mmap(nil, SHM_SIZE, C.PROT_READ|C.PROT_WRITE, C.MAP_SHARED, fd, 0)
if err != nil {
fmt.Println(err)
return
}
C.close(fd)
data := (*MyData)(unsafe.Pointer(ptr))
data.Col1 = 100
data.Col2 = 876
data.Col3 = 8021
}
下面是shm_reader.go的代碼:
復制代碼 代碼如下:
package main
/*
#cgo linux LDFLAGS: -lrt
#include fcntl.h>
#include unistd.h>
#include sys/mman.h>
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
int my_shm_open(char *name) {
return shm_open(name, O_RDWR);
}
*/
import "C"
import (
"fmt"
"unsafe"
)
const SHM_NAME = "my_shm"
const SHM_SIZE = 4 * 1000 * 1000 * 1000
type MyData struct {
Col1 int
Col2 int
Col3 int
}
func main() {
fd, err := C.my_shm_open(C.CString(SHM_NAME))
if err != nil {
fmt.Println(err)
return
}
ptr, err := C.mmap(nil, SHM_SIZE, C.PROT_READ|C.PROT_WRITE, C.MAP_SHARED, fd, 0)
if err != nil {
fmt.Println(err)
return
}
C.close(fd)
data := (*MyData)(unsafe.Pointer(ptr))
fmt.Println(data)
}
上面的程序映射了一塊4G的虛擬內存,用來證明mmap沒有實際占用4G內存,而是用到了虛擬內存。
shm_writer創(chuàng)建好共享內存以后,往內存區(qū)域寫入了一個結構體,shm_reader則讀出一個結構體。
內嵌的C代碼中有一行 :
復制代碼 代碼如下:
#cgo linux LDFLAGS: -lrt
因為mmap在Mac上不需要連接librt,在linux上則需要,所以做了一個條件鏈接,這是cgo提供的功能。
上面代碼中還用到一個cgo的技巧,像shm_open和mmap函數在錯誤時會返回errno,如果我們在go中使用多返回值語法,cgo會自己把錯誤碼轉換成錯誤信息,很方便的功能。
希望本文所述對大家的Go語言程序設計有所幫助。
您可能感興趣的文章:- Golang 內存模型詳解(一)
- Go語言中的Array、Slice、Map和Set使用詳解
- Go語言的GOPATH與工作目錄詳解
- Go語言命令行操作命令詳細介紹
- Go語言interface詳解
- Go語言運行環(huán)境安裝詳細教程
- Go語言實現簡單的一個靜態(tài)WEB服務器
- GO語言并發(fā)編程之互斥鎖、讀寫鎖詳解
- GO語言標準錯誤處理機制error用法實例
- Go語言中的內存布局詳解