项目场景
在 Golang1.19.x 版本下,项目中需要将日志输出到指定文件内(原生开发),故需要每隔一段时间将日志文件进行移动,并创建新的日志文件继续参与日志记录。
问题描述
在进行使用中日志文件移动时,windows 下通过 os.Rename() 不生效。
通过追踪源码,可发现该操作将导致错误 golang.org/x/sys/windows.ERROR_SHARING_VIOLATION (32)。
// eg: D:/log/a.log -> D:/log/a.1.log
os.Rename(oldFileFullPath, backFileFullPath)
原因分析
在Golang中,"ERROR_SHARING_VIOLATION"是一个错误信息,通常与并发编程相关。它表示两个或多个Goroutines试图同时访问共享资源,而没有进行适当的同步操作,导致了竞态条件(race condition)。
要解决这个错误,可以采取以下几种方法之一:
- 使用互斥锁(Mutex):互斥锁可以确保在同一时间只有一个Goroutine能够访问共享资源。你可以在访问共享资源的代码段前加锁,并在访问完成后解锁。下面是一个示例代码片段:
package main
import (
"fmt"
"sync"
)
var sharedResource = 0
func main() {
var wg sync.WaitGroup
wg.Add(2)
// 第一个Goroutine
go func() {
defer wg.Done()
sharedResource++
}()
// 第二个Goroutine
go func() {
defer wg.Done()
sharedResource--
}()
wg.Wait()
fmt.Println("Final value of shared resource:", sharedResource)
}
在上面的示例中,使用sync.WaitGroup来等待两个Goroutines完成,并使用互斥锁来保护对共享资源的访问。
- 使用原子操作(Atomic Operations):如果你的操作仅限于单个变量,你可以使用原子操作来确保对其的并发访问是安全的。Golang提供了
sync/atomic包,其中包含了一些原子操作类型,例如int32,int64,float32,float64等。下面是一个使用原子操作的示例代码片段:
package main
import (
"fmt"
"sync"
"sync/atomic"
)
var sharedResource int32
var mutex sync.Mutex
func main() {
var wg sync.WaitGroup
wg.Add(2)
// 第一个Goroutine
go func() {
mutex.Lock()
atomic.AddInt32(&sharedResource, 1)
mutex.Unlock()
}()
// 第二个Goroutine
go func() {
mutex.Lock()
atomic.AddInt32(&sharedResource, -1)
mutex.Unlock()
}()
wg.Wait()
fmt.Println("Final value of shared resource:", sharedResource)
}
在上面的示例中,使用了sync.Mutex来保护对共享资源的访问,并使用原子操作atomic.AddInt32来安全地增加或减少sharedResource的值。
总结
windows 环境下使用 Golang 进行使用中文件的移动操作将产生错误,该错误无法直接避免。
故,如果环境允许,可使用虚拟机或基于 docker + vscode 的开发方式,该开发方式可避免多数问题并提高工作效率。
本文讨论了在Golang1.19中遇到的文件移动错误ERROR_SHARING_VIOLATION,源于并发编程中的竞态条件。通过使用互斥锁和原子操作,提供了解决方案以确保在Windows环境下日志文件的安全移动。
608

被折叠的 条评论
为什么被折叠?



