go 如何保证 同一时间只有一个线程能访问资源

在 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
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值