可能遇到的问题
- 数据竞争(Race Condition):多个协程同时读写字符串,可能导致数据不一致。比如一个协程读取字符串时,另一个协程正在修改它,使得读取到的内容不完整或错误。
- 内存损坏:如果多个协程无保护地同时修改字符串内容,可能导致内存中字符串的表示被破坏,引发程序崩溃。
解决方案
- 互斥锁(Mutex):使用
sync.Mutex
来保护对字符串的操作。在读取或修改字符串之前,先获取锁,操作完成后释放锁。这样同一时间只有一个协程能访问字符串,避免数据竞争。
- 通道(Channel):通过通道来传递字符串操作的请求,由一个专门的协程负责处理这些请求,从而避免多个协程直接操作字符串带来的竞争问题。
示例代码(使用互斥锁)
package main
import (
"fmt"
"sync"
)
var (
str string
mu sync.Mutex
wg sync.WaitGroup
)
func modifyString(newStr string) {
defer wg.Done()
mu.Lock()
str = newStr
mu.Unlock()
}
func readString() {
defer wg.Done()
mu.Lock()
fmt.Println("Read string:", str)
mu.Unlock()
}
func main() {
str = "initial"
wg.Add(2)
go modifyString("new value")
go readString()
wg.Wait()
}
示例代码(使用通道)
package main
import (
"fmt"
"sync"
)
type StringOp struct {
op string
value string
reply chan string
}
func stringOperator(ch <-chan StringOp) {
var str string
for op := range ch {
switch op.op {
case "modify":
str = op.value
op.reply <- "Modified"
case "read":
op.reply <- str
}
}
}
func main() {
var wg sync.WaitGroup
ch := make(chan StringOp)
go stringOperator(ch)
// 修改字符串
wg.Add(1)
reply := make(chan string)
ch <- StringOp{op: "modify", value: "new value", reply: reply}
go func() {
defer wg.Done()
fmt.Println(<-reply)
}()
// 读取字符串
wg.Add(1)
reply2 := make(chan string)
ch <- StringOp{op: "read", reply: reply2}
go func() {
defer wg.Done()
fmt.Println("Read string:", <-reply2)
}()
close(ch)
wg.Wait()
}