golang操作共享内存

423 阅读1分钟

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")
	}
}

截屏2023-09-06 14.59.25.png

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")
	}
}

截屏2023-09-06 15.05.34.png 源代码地址