SoFunction
Updated on 2025-03-03

Analysis of Go shared memory reading and writing examples

This article analyzes the method of reading and writing shared memory in Go language in examples. Share it for your reference. The specific analysis is as follows:

Previously, the Go language pointer operation and embedded C code were analyzed, and an experiment on shared memory reading and writing in Go language was conducted.

Let’s first talk about what shared memory is. We know that the memory seen by different processes is independent of each other and there is no way to directly operate the data within each other. Shared memory relies on the memory mapping mechanism provided by the operating system to map a piece of address space of different processes to the same virtual memory area, so that different processes can operate on a shared memory block. Shared memory is the most efficient inter-process communication mechanism because data does not need to be copied between the kernel and the program.

Shared memory uses the mmap function provided by the system. It can map a file to an area of ​​virtual memory. The program uses a pointer to refer to this area. The operations on this memory area will be written back to the file. Go's built-in syscall package has mmap function, but it is encapsulated and returns []byte. It cannot do the pointer operation I need, so I still use cgo to call the native mmap.

The experiment is divided into two programs: read and write, so that we can observe that the read process can read the information written to the shared memory by the write process.

Here is the code for shm_writer.go:

Copy the codeThe code is as follows:
package main
/*
#cgo linux LDFLAGS: -lrt
#include <>
#include <>
#include <sys/>
#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((SHM_NAME))
    if err != nil {
        (err)
        return
    }
    (fd, SHM_SIZE)
    ptr, err := (nil, SHM_SIZE, C.PROT_READ|C.PROT_WRITE, C.MAP_SHARED, fd, 0)
    if err != nil {
        (err)
        return
    }
    (fd)
    data := (*MyData)((ptr))
    data.Col1 = 100
    data.Col2 = 876
    data.Col3 = 8021
}

Here is the code for shm_reader.go:

Copy the codeThe code is as follows:
package main
/*
#cgo linux LDFLAGS: -lrt
#include <>
#include <>
#include <sys/>
#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((SHM_NAME))
    if err != nil {
        (err)
        return
    }
    ptr, err := (nil, SHM_SIZE, C.PROT_READ|C.PROT_WRITE, C.MAP_SHARED, fd, 0)
    if err != nil {
        (err)
        return
    }
    (fd)
    data := (*MyData)((ptr))
    (data)
}

The above program maps a 4G virtual memory to prove that mmap does not actually occupy 4G memory, but uses virtual memory.

After the shm_writer creates shared memory, a structure is written into the memory area, and the shm_reader reads out a structure.

There is a line in the embedded C code:

Copy the codeThe code is as follows:
#cgo linux LDFLAGS: -lrt

Because mmap does not need to connect to librt on Mac, but on Linux, a conditional link is made, which is a feature provided by Cgo.

The above code also uses a CG technique, such as shm_open and mmap functions that return errno when errors are made. If we use the multi-return value syntax in go, cgo will convert the error code into error information by itself, which is a very convenient function.

I hope this article will be helpful to everyone's Go language programming.