
在 Go 并发编程中,多个 Goroutine 同时访问和修改共享变量时,如果没有适当的同步机制,就会出现竞态条件,导致程序行为不可预测。本文将深入探讨如何使用 sync.Mutex 互斥锁来解决这个问题,并提供代码示例,帮助开发者构建安全可靠的并发程序。
sync.Mutex 是 Go 语言标准库 sync 包提供的一种互斥锁,用于保护临界区,确保同一时刻只有一个 Goroutine 可以访问被保护的共享资源。
以下是一个使用 sync.Mutex 封装计数器的示例:
package main
import (
"fmt"
"net/http"
"sync"
)
type Counter struct {
mu sync.Mutex
x int64
}
func (c *Counter) Add(x int64) {
c.mu.Lock() // 获取锁
c.x += x
c.mu.Unlock() // 释放锁
}
func (c *Counter) Value() (x int64) {
c.mu.Lock() // 获取锁
x = c.x
c.mu.Unlock() // 释放锁
return
}
func makeHomeHandler() func(http.ResponseWriter, *http.Request) {
var views Counter
return func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Counting %s, %d so far.\n", r.URL.Path[1:], views.Value())
views.Add(1)
}
}
func main() {
http.HandleFunc("/", makeHomeHandler())
fmt.Println("Server listening on port 8080")
http.ListenAndServe(":8080", nil)
}在这个例子中,Counter 结构体包含一个 sync.Mutex 类型的 mu 字段和一个 int64 类型的 x 字段,用于存储计数器的值。Add 和 Value 方法都使用 mu.Lock() 获取锁,并在方法结束前使用 mu.Unlock() 释放锁。这样就保证了对 x 字段的并发访问是安全的。
注意事项:
对于 HTTP 处理程序,可以定义一个实现了 http.Handler 接口的类型,将互斥锁和计数器封装在类型内部,从而简化代码结构。
以下是一个使用 http.Handler 接口的示例:
package main
import (
"fmt"
"net/http"
"sync"
)
type homeHandler struct {
mu sync.Mutex
views int64
}
func (h *homeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.mu.Lock()
defer h.mu.Unlock()
fmt.Fprintf(w, "Counting %s, %d so far.\n", r.URL.Path[1:], h.views)
h.views++
}
func main() {
http.Handle("/", new(homeHandler))
fmt.Println("Server listening on port 8080")
http.ListenAndServe(":8080", nil)
}在这个例子中,homeHandler 结构体实现了 http.Handler 接口的 ServeHTTP 方法。在 ServeHTTP 方法中,使用 h.mu.Lock() 获取锁,并使用 defer h.mu.Unlock() 确保锁的释放。这样就保证了对 h.views 字段的并发访问是安全的。
总结:
以上就是Go 并发编程:使用 Mutex 保护共享变量的详细内容,更多请关注php中文网其它相关文章!
编程怎么学习?编程怎么入门?编程在哪学?编程怎么学才快?不用担心,这里为大家提供了编程速学教程(入门课程),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号