在 Go 语言中,可以通过多种方式来确保同一时间只有一个 goroutine(轻量级线程)能访问共享资源。这通常涉及到使用互斥锁(Mutex)、**读写锁(RWMutex)或信号量(Semaphore)**等同步机制。以下是一些常用的方法:
1. 使用互斥锁(Mutex)
互斥锁是最基本的同步原语,用于保护共享资源。Go 的 sync 包提供了 Mutex 类型。
package main
import (
"fmt"
"sync"
)
// 定义一个共享资源
var (
counter int
mu sync.Mutex // 创建一个互斥锁
)
func increment(wg *sync.WaitGroup) {
defer wg.Done() // 通知 WaitGroup 当前 goroutine 完成
mu.Lock() // 加锁,进入临界区
counter++ // 对共享资源进行操作
mu.Unlock() // 解锁,退出临界区
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 1000; i++ {
wg.Add(1) // 添加一个 goroutine 到 WaitGroup
go increment(&wg) // 启动 goroutine
}
wg.Wait() // 等待所有 goroutine 完成
fmt.Println("Final counter value:", counter)
}
2. 使用读写锁(RWMutex)
当有多个 goroutine 需要读取共享资源,但只有一个需要写入时,使用读写锁可以提高性能。读写锁允许多个读操作同时进行,但在写操作时会阻塞所有读操作。
package main
import (
"fmt"
"sync"
)
var (
value int
rwMu sync.RWMutex // 创建一个读写锁
)
func read(wg *sync.WaitGroup) {
defer wg.Done()
rwMu.RLock() // 加读锁
fmt.Println("Reading value:", value)
rwMu.RUnlock() // 解读锁
}
func write(wg *sync.WaitGroup, newValue int) {
defer wg.Done()
rwMu.Lock() // 加写锁
value = newValue
fmt.Println("Writing value:", newValue)
rwMu.Unlock() // 解写锁
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go read(&wg) // 启动读取 goroutine
}
for i := 0; i < 2; i++ {
wg.Add(1)
go write(&wg, i) // 启动写入 goroutine
}
wg.Wait() // 等待所有 goroutine 完成
}
3. 使用信号量
信号量可以用于限制同一时间内允许访问资源的 goroutine 数量,通常用于控制对资源的并发访问。
package main
import (
"fmt"
"sync"
"time"
)
var (
semaphore = make(chan struct{}, 1) // 创建一个信号量,容量为 1
)
func accessResource(id int) {
semaphore <- struct{}{} // 获取信号量
fmt.Printf("Goroutine %d accessing resource\n", id)
time.Sleep(2 * time.Second) // 模拟访问资源的时间
fmt.Printf("Goroutine %d releasing resource\n", id)
<-semaphore // 释放信号量
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
accessResource(id)
}(i)
}
wg.Wait() // 等待所有 goroutine 完成
}
4. 使用 Channel 作为互斥锁
package main
import (
"fmt"
)
var lock = make(chan struct{}, 1) // 创建一个带缓冲的信道
func criticalSection(id int) {
lock <- struct{}{} // 尝试获取锁
fmt.Printf("Goroutine %d in critical section\n", id)
// 模拟工作
lock <- struct{}{} // 释放锁
}
func main() {
for i := 0; i < 5; i++ {
go criticalSection(i)
}
// 等待一段时间以确保所有 goroutine 完成
// 这里可以使用 WaitGroup
}

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



