请先直接下载代码的,走这里:
- https://github.com/gzg1984/go_sem.git
代码中的原理讲解:
r1, _, _ := syscall.Syscall(syscall.SYS_SEMGET, uintptr(key),uintptr(1), uintptr(00666))
go没有直接调用系统调用的能力,要用syscall方式转换一次。第一个参数是系统调用编号。
在mac和linux上这个值不一样,重编后两边都可以用。
r1, r2, err := syscall.Syscall6(syscall.SYS_SEMCTL,
uintptr(semid),
uintptr(0),
uintptr(C.SETVAL),
uintptr(newInit),
uintptr(0), uintptr(0))
go只给了syscall.Syscall和syscall.Syscall6两个固定参数个数的系统调用方式,但是semctl实际上是semid,number,action,semun 4个参数。
这个调用实现有两个不直观的知识点:
1: 对于4参数的系统调用,用6参数的syscal6实现,最后有两个0来补齐参数个数
2: 对于semun参数,由于go对union支持得不好,所以这里直接用了int作为参数。
r1, r2, err := syscall.Syscall(syscall.SYS_SEMOP, uintptr(semid), uintptr(unsafe.Pointer(&stSemBuf)), 1)
这里的重点是:
一个go里的结构体,如何转化为系统调用使用的指针。
方法是用unsafe.Pointer转化。
测试方法:
./go_sem_tool -k 1 &
# 此时一个进程在后台锁住信号量并运行
./go_sem_tool -k 1
# 此时一个进程在前台尝试锁住信号量,会失败退出
# 十秒后后台进程执行完后,再执行此命令会成功。