如何在Golang中创建命名互斥锁?复刻Windows CreateMutex逻辑
在Go中实现Windows命名互斥锁
Go标准库的sync.Mutex仅支持进程内部的同步,无法实现Windows API中CreateMutex那样的跨进程命名互斥锁。要实现跨进程同步,必须直接调用Windows系统API,以下是两种可行方案:
方案一:使用golang.org/x/sys/windows包(推荐)
这是Go官方提供的系统调用扩展包,使用更安全、便捷。先执行安装命令:
go get golang.org/x/sys/windows
示例代码:
package main import ( "golang.org/x/sys/windows" "log" ) func main() { // 将互斥锁名称转换为Windows要求的UTF-16指针 mutexName, err := windows.UTF16PtrFromString("NameOfMutexObject") if err != nil { log.Fatal(err) } // 对应Windows API的CreateMutex调用 // 参数:安全描述符(nil对应NULL)、初始拥有者(false对应FALSE)、互斥锁名称 hMutex, err := windows.CreateMutex(nil, false, mutexName) if err != nil { log.Fatalf("创建互斥锁失败: %v", err) } // 确保程序退出时释放句柄 defer windows.CloseHandle(hMutex) // 等待获取互斥锁,INFINITE表示无限等待 waitResult, err := windows.WaitForSingleObject(hMutex, windows.INFINITE) if err != nil { log.Fatalf("等待互斥锁失败: %v", err) } switch waitResult { case windows.WAIT_OBJECT_0: log.Println("成功获取互斥锁") // 在此执行需要跨进程同步的操作 // ... // 操作完成后释放互斥锁 if err := windows.ReleaseMutex(hMutex); err != nil { log.Fatalf("释放互斥锁失败: %v", err) } case windows.WAIT_ABANDONED: log.Println("获取到被遗弃的互斥锁(之前持有锁的进程异常退出)") } }
方案二:直接调用kernel32.dll(不推荐,依赖syscall已弃用)
如果不想引入第三方包,可以直接通过syscall调用Windows原生API,但syscall在Go 1.16后已被标记为弃用,仅作兼容参考:
package main import ( "log" "syscall" "unsafe" ) var ( kernel32 = syscall.NewLazyDLL("kernel32.dll") createMutexW = kernel32.NewProc("CreateMutexW") waitForSingleObject = kernel32.NewProc("WaitForSingleObject") releaseMutex = kernel32.NewProc("ReleaseMutex") closeHandle = kernel32.NewProc("CloseHandle") ) func main() { mutexName, err := syscall.UTF16PtrFromString("NameOfMutexObject") if err != nil { log.Fatal(err) } // 调用CreateMutexW hMutex, _, err := createMutexW.Call(0, 0, uintptr(unsafe.Pointer(mutexName))) if hMutex == 0 { log.Fatalf("创建互斥锁失败: %v", err) } defer func() { _, _, _ = closeHandle.Call(hMutex) }() // 等待获取锁 result, _, err := waitForSingleObject.Call(hMutex, uintptr(syscall.INFINITE)) switch result { case uintptr(syscall.WAIT_OBJECT_0): log.Println("成功获取互斥锁") // 执行同步操作 // ... // 释放锁 _, _, err := releaseMutex.Call(hMutex) if err != syscall.Errno(0) { log.Fatalf("释放互斥锁失败: %v", err) } case uintptr(syscall.WAIT_ABANDONED): log.Println("获取到被遗弃的互斥锁") default: log.Fatalf("等待锁失败: %v", err) } }
关键说明
- 命名互斥锁是系统级资源,不同进程使用相同名称即可共享该锁
- 必须在使用完成后调用
CloseHandle释放句柄,避免资源泄漏 - 如果创建时将
bInitialOwner设为true,当前进程会直接持有锁,需手动调用ReleaseMutex释放
内容的提问来源于stack exchange,提问作者stubble jumper
相关产品推荐
相关产品推荐

