몇 줄 바꿔봤다. 원래는
푸시/팝에서 형을 지정하지 않고 인터페이스를 썼다. void * 구만?
대충 뮤텍스로 감쌌음..
package main
import (
"unsafe"
"os"
"fmt"
"syscall"
"reflect"
// "flag"
"golang.org/x/sys/unix"
"sync"
"time"
)
var mutex = &sync.Mutex{}
const DATA_SIZE int = 16
type data struct {
// klen int
v [DATA_SIZE]byte
}
const INT_SIZE int = int(unsafe.Sizeof(int(0)))
const MAX_ITEM int = 1000000
const ITEM_SIZE int = int(unsafe.Sizeof(data{}))
const FILE_SIZE int = ITEM_SIZE * MAX_ITEM
type data_file struct {
pos1 int
dummy1 [4096 - INT_SIZE]byte
items [MAX_ITEM]data
dummy3 [4096 - (MAX_ITEM * ITEM_SIZE) % 4096]byte
pos2 int
dummy2 [4096 - INT_SIZE]byte
}
func Open_data(init bool, filename string) []data_file {
size := int(unsafe.Sizeof( data_file{} ))
println(size)
var map_file *os.File
var err error
if init {
map_file, err = os.Create(filename)
} else {
map_file, err = os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_SYNC, 0755)
}
defer map_file.Close()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
_, err = map_file.Seek(int64(size - 1), 0)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
_, err = map_file.Write([]byte{0})
if err != nil {
fmt.Println(err)
os.Exit(1)
}
mmap, err := syscall.Mmap(int(map_file.Fd()), 0, int(size), syscall.PROT_READ | syscall.PROT_WRITE, syscall.MAP_SHARED)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
if init {
for i := range mmap {
mmap[i] = 0
}
}
header := (*reflect.SliceHeader)(unsafe.Pointer(&mmap))
header.Len = 1
header.Cap = 1
map_data := *(*[]data_file)(unsafe.Pointer(header))
err = map_file.Close()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
return map_data
}
func Close_data(mmap []data_file) {
header := (*reflect.SliceHeader)(unsafe.Pointer(&mmap))
header.Len = int(unsafe.Sizeof(data_file{}))
header.Cap = header.Len
unmap := *(*[]byte)(unsafe.Pointer(&mmap))
err := syscall.Munmap(unmap)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}
var sp int = 0
var gpos1 *int
var gpos2 *int
var max_pos *int
//func push(item_data []byte, store []data_file ) {
func push(item_data interface{}, store []data_file ) {
var item_byte []byte
switch item_data.(type) {
case []byte:
item_byte = item_data.([]byte)
case string:
item_byte = []byte(item_data.(string))
default:
}
// item_byte := item_data.([]byte)
item_byte = append(item_byte, 0)
mutex.Lock()
if sp == MAX_ITEM {
fmt.Fprintf(os.Stderr, "용량 초과, 마지막 푸시 = %s\n", string(item_byte))
return
}
copy(store[0].items[*gpos1].v[:], item_byte)
*gpos1++
*gpos2++
sp++
mutex.Unlock()
}
func pop(store []data_file ) (ret interface{}) {
mutex.Lock()
sp--
if sp < 0 {
// ret = []byte("")
ret = nil
fmt.Fprintf(os.Stderr, "스택이 비었음\n")
sp = 0
return
}
*gpos1--
*gpos2--
ret = store[0].items[*gpos1].v[:]
mutex.Unlock()
return
}
func main() {
println(FILE_SIZE)
// file := flag.String("file", "stack.dat", "스택 저장소 파일 이름")
// max_items := flag.Int("max-item", MAX_ITEM, "최대 아이템 갯수")
// bucket_size := flag.Int("bucket-size", DATA_SIZE, "버킷 크기")
my_data := Open_data(true, "my_data.dat")
header := (*reflect.SliceHeader)(unsafe.Pointer(&my_data[0].pos1))
header.Len = 4096
header.Cap = 4096
unix.Msync(*(*[]byte)(unsafe.Pointer(header)), unix.MS_SYNC)
header = (*reflect.SliceHeader)(unsafe.Pointer(&my_data[0].pos2))
header.Len = 4096
header.Cap = 4096
unix.Msync(*(*[]byte)(unsafe.Pointer(header)), unix.MS_SYNC)
gpos1 = &my_data[0].pos1
gpos2 = &my_data[0].pos2
sp = *gpos1
for i := 0; i < 10000; i++ {
go push(fmt.Sprintf("-- %d --", i), my_data)
}
time.Sleep(time.Duration(1) * time.Second)
for i := 0; i < 10000; i++ {
go func() {
a := pop(my_data)
if a != nil {
println(string(a.([]byte)))
}
} ()
}
time.Sleep(time.Duration(4) * time.Second)
// println(string(pop(my_data).([]byte)))
os.Exit(0)
// println(string(pop(my_data).([]byte)))
// os.Exit(0)
push("가나", my_data)
println(string(pop(my_data).([]byte)))
push([]byte("가나--"), my_data)
println(string(pop(my_data).([]byte)))
// push(다라"), my_data)
push([]byte("마바"), my_data)
push([]byte("하하"), my_data)
push([]byte("호호"), my_data)
println(string(pop(my_data).([]byte)))
println(string(pop(my_data).([]byte)))
println()
push([]byte("추가1"), my_data)
push([]byte("추가2"), my_data)
println(string(pop(my_data).([]byte)))
/*
for {
a := pop(my_data)
if a != nil {
println(string(a))
} else {
break
}
}
*/
defer Close_data(my_data)
}