golang操作共享内存
本文主要使用共享内存实现一个共享计数器
System V共享内存
上代码
package main
/*
#include <sys/shm.h>
#include <stdint.h>
*/
import "C"
import (
"fmt"
"syscall"
"unsafe"
)
// system v share memory open
func GetShare_Mem[T int | int32 | int64](shmid int, dst_ptr **T) uintptr {
shm, _, err := syscall.Syscall(syscall.SYS_SHMAT, uintptr(shmid), 0, 0)
if len(err.Error()) < 1 {
*dst_ptr = (*T)(unsafe.Pointer(shm))
return 0
}
return shm
}
func CreateShare_Mem[T int | int32 | int64](pathname string, gendid int, dst_ptr **T) uintptr {
pn := C.CString(pathname)
key := C.ftok(pn, (C.int)(gendid))
C.free(unsafe.Pointer(pn))
var te T
shmid, _, err := syscall.Syscall(syscall.SYS_SHMGET, uintptr(key), unsafe.Sizeof(te), 01000|0640)
if err != 0 {
fmt.Println("[error]", err.Error())
return 0
}
var sharemem uintptr
sharemem, _, err = syscall.Syscall(syscall.SYS_SHMAT, shmid, 0, 0)
if err != 0 {
fmt.Println("[error]", err.Error())
return 0
}
*dst_ptr = (*T)(unsafe.Pointer(sharemem))
return shmid
}
// system v share memory close
func Close_Share_Mem(shm uintptr) error {
_, _, err := syscall.Syscall(syscall.SYS_SHMDT, shm, 0, 0)
if len(err.Error()) > 0 {
return fmt.Errorf(err.Error())
}
return nil
}
Posix 共享内存
[注意] mac和freebsd可能由于缺少/dev/shm会导致打开文件时遇到问题,不过别着急,如果你是在mac和freebsd上运行,将shm_open替换为普通的open就行了。
package main
/*
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/mman.h>
void* open_shm(char* pathname,int sizes){
int shmid=shm_open(pathname,O_RDWR|O_CREAT,0640);
if (shmid>0){
if(ftruncate(shmid,sizes)!=-1){
void* ans=mmap(NULL,sizes,PROT_READ|PROT_WRITE,MAP_SHARED,shmid,0);
if(ans!=MAP_FAILED){
return ans;
}else{
fprintf(stderr,"mmap failed\n");
}
}else{
fprintf(stderr,"ftruncate failed\n");
}
}else{
fprintf(stderr,"open shmid failed\n");
}
return 0;
}
void unmap(void* src,int sizes){
msync(src,sizes,MS_SYNC);
munmap(src,sizes);
}
*/
import "C"
import (
"fmt"
"syscall"
"unsafe"
)
// posix share memory interface
func Shm_Open[T int | int32 | int64](pathname string, dst **T) unsafe.Pointer {
pathinfo := C.CString(pathname)
var te T
ansptr := C.open_shm(pathinfo, (C.int)(unsafe.Sizeof(te)))
if ansptr != nil {
*dst = (*T)(unsafe.Pointer(ansptr))
}
C.free(unsafe.Pointer(pathinfo))
return ansptr
}
// posix share memory close interface
func Shm_Close(ptr unsafe.Pointer, sizes int) {
C.unmap(ptr, (C.int)(sizes))
}
// posix share memory delete interface
func Shm_Del(shm_name string) {
shm_cname := C.CString(shm_name)
C.shm_unlink(shm_cname)
C.free(unsafe.Pointer(shm_cname))
}
结果演示
使用到的main函数
package main
import (
"fmt"
"unsafe"
"github.com/oswaldoooo/cmicro/sys"
)
//posix
func main() {
var te *int32
ptr := sys.Shm_Open("counter.shm", &te)
if ptr != nil {
defer sys.Shm_Close(ptr, int(unsafe.Sizeof(*te)))
fmt.Println("get counter val", *te)
*te += 1
} else {
fmt.Println("[error] get counter ptr failed")
}
}
package main
import (
"fmt"
"github.com/oswaldoooo/cmicro/sys"
)
//system v
func main() {
var te *int32
ptr := sys.CreateShare_Mem("./", 10, &te)
if ptr != 0 {
defer sys.Close_Share_Mem(ptr)
fmt.Println("get value", *te, ";shmid", ptr)
*te += 1
} else {
fmt.Println("[error] create share memory failed")
}
}