面试题答案
一键面试常见并发编程场景及atomic包使用说明
- 计数器场景
- 场景描述:在并发环境下,多个goroutine可能会同时对一个计数器进行增加或减少操作。如果直接使用普通变量进行操作,可能会因为竞态条件导致结果不准确。
- atomic包使用:
package main
import (
"fmt"
"sync"
"sync/atomic"
)
func main() {
var count int64
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
atomic.AddInt64(&count, 1)
}()
}
wg.Wait()
fmt.Println("Final count:", atomic.LoadInt64(&count))
}
在这个例子中,atomic.AddInt64
函数用于安全地增加count
的值,atomic.LoadInt64
函数用于读取count
的值,避免了竞态条件。
- 状态标志场景
- 场景描述:在并发程序中,需要一个标志来表示某个操作是否完成或某个状态是否改变,多个goroutine可能会同时尝试修改这个标志。
- atomic包使用:
package main
import (
"fmt"
"sync"
"sync/atomic"
)
func main() {
var status int32 = 0
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
// 模拟一些操作
atomic.StoreInt32(&status, 1)
}()
wg.Wait()
if atomic.LoadInt32(&status) == 1 {
fmt.Println("Operation completed")
}
}
这里atomic.StoreInt32
用于设置状态标志,atomic.LoadInt32
用于读取状态标志,保证在并发环境下状态标志的正确读写。
- 指针操作场景
- 场景描述:当在并发环境下需要安全地更新一个指针时,如果直接操作指针,可能会导致竞态条件。
- atomic包使用:
package main
import (
"fmt"
"sync"
"sync/atomic"
)
type Data struct {
value int
}
func main() {
var ptr *Data
var wg sync.WaitGroup
wg.Add(1)
newData := &Data{value: 10}
go func() {
defer wg.Done()
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&ptr)), unsafe.Pointer(newData))
}()
wg.Wait()
result := (*Data)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&ptr))))
fmt.Println("Value from pointer:", result.value)
}
在这个例子中,通过atomic.StorePointer
和atomic.LoadPointer
来安全地更新和读取指针,确保在并发环境下指针操作的正确性。