当前位置: 首页 > web >正文

Go语言多线程问题

打印零与奇偶数(leetcode 1116)

方法1:使用互斥锁和条件变量

package mainimport ("fmt""sync"
)type ZeroEvenOdd struct {n         intzeroMutex sync.MutexevenMutex sync.MutexoddMutex  sync.Mutexcurrent   int
}func NewZeroEvenOdd(n int) *ZeroEvenOdd {z := &ZeroEvenOdd{n: n}z.evenMutex.Lock()z.oddMutex.Lock()return z
}func (z *ZeroEvenOdd) Zero(printNumber func(int)) {for i := 0; i < z.n; i++ {z.zeroMutex.Lock()printNumber(0)z.current++if z.current%2 == 1 {z.oddMutex.Unlock()} else {z.evenMutex.Unlock()}}
}func (z *ZeroEvenOdd) Even(printNumber func(int)) {for i := 2; i <= z.n; i += 2 {z.evenMutex.Lock()printNumber(i)z.zeroMutex.Unlock()}
}func (z *ZeroEvenOdd) Odd(printNumber func(int)) {for i := 1; i <= z.n; i += 2 {z.oddMutex.Lock()printNumber(i)z.zeroMutex.Unlock()}
}func main() {n := 5zeo := NewZeroEvenOdd(n)var wg sync.WaitGroupwg.Add(3)printFunc := func(x int) {fmt.Print(x)}go func() {defer wg.Done()zeo.Zero(printFunc)}()go func() {defer wg.Done()zeo.Even(printFunc)}()go func() {defer wg.Done()zeo.Odd(printFunc)}()wg.Wait()fmt.Println()
}

方法2:使用通道同步

package mainimport ("fmt""sync"
)type ZeroEvenOdd struct {n       intzeroCh  chan struct{}evenCh  chan struct{}oddCh   chan struct{}done    chan struct{}
}func NewZeroEvenOdd(n int) *ZeroEvenOdd {z := &ZeroEvenOdd{n:      n,zeroCh: make(chan struct{}),evenCh: make(chan struct{}),oddCh:  make(chan struct{}),done:   make(chan struct{}),}close(z.zeroCh) // 初始允许zero执行return z
}func (z *ZeroEvenOdd) Zero(printNumber func(int)) {for i := 0; i < z.n; i++ {<-z.zeroChprintNumber(0)if i%2 == 0 {z.oddCh <- struct{}{}} else {z.evenCh <- struct{}{}}}close(z.done)
}func (z *ZeroEvenOdd) Even(printNumber func(int)) {for i := 2; i <= z.n; i += 2 {<-z.evenChprintNumber(i)z.zeroCh <- struct{}{}}
}func (z *ZeroEvenOdd) Odd(printNumber func(int)) {for i := 1; i <= z.n; i += 2 {<-z.oddChprintNumber(i)z.zeroCh <- struct{}{}}
}func main() {n := 5zeo := NewZeroEvenOdd(n)var wg sync.WaitGroupwg.Add(3)printFunc := func(x int) {fmt.Print(x)}go func() {defer wg.Done()zeo.Zero(printFunc)}()go func() {defer wg.Done()zeo.Even(printFunc)}()go func() {defer wg.Done()zeo.Odd(printFunc)}()wg.Wait()fmt.Println()
}

方法3:使用原子计数器

package mainimport ("fmt""sync""sync/atomic"
)type ZeroEvenOdd struct {n       intcurrent int32cond    *sync.Cond
}func NewZeroEvenOdd(n int) *ZeroEvenOdd {return &ZeroEvenOdd{n:       n,current: 0,cond:    sync.NewCond(&sync.Mutex{}),}
}func (z *ZeroEvenOdd) Zero(printNumber func(int)) {for i := 0; i < z.n; i++ {z.cond.L.Lock()for atomic.LoadInt32(&z.current) != 0 {z.cond.Wait()}printNumber(0)atomic.StoreInt32(&z.current, int32(i+1))z.cond.Broadcast()z.cond.L.Unlock()}
}func (z *ZeroEvenOdd) Even(printNumber func(int)) {for i := 2; i <= z.n; i += 2 {z.cond.L.Lock()for atomic.LoadInt32(&z.current) != int32(i) {z.cond.Wait()}printNumber(i)atomic.StoreInt32(&z.current, 0)z.cond.Broadcast()z.cond.L.Unlock()}
}func (z *ZeroEvenOdd) Odd(printNumber func(int)) {for i := 1; i <= z.n; i += 2 {z.cond.L.Lock()for atomic.LoadInt32(&z.current) != int32(i) {z.cond.Wait()}printNumber(i)atomic.StoreInt32(&z.current, 0)z.cond.Broadcast()z.cond.L.Unlock()}
}func main() {n := 5zeo := NewZeroEvenOdd(n)var wg sync.WaitGroupwg.Add(3)printFunc := func(x int) {fmt.Print(x)}go func() {defer wg.Done()zeo.Zero(printFunc)}()go func() {defer wg.Done()zeo.Even(printFunc)}()go func() {defer wg.Done()zeo.Odd(printFunc)}()wg.Wait()fmt.Println()
}

哲学家进食

package mainimport ("fmt""sync""time"
)const numPhilosophers = 5type Philosopher struct {id          intleftFork    *sync.MutexrightFork   *sync.MutexeatingTimes int
}func (p *Philosopher) think() {fmt.Printf("哲学家 %d 正在思考...\n", p.id)time.Sleep(time.Second * 1)
}func (p *Philosopher) eat() {// 确定拿叉子的顺序(避免循环等待)first, second := p.leftFork, p.rightForkif p.id%2 == 0 { // 偶数ID哲学家先拿右叉子first, second = p.rightFork, p.leftFork}// 获取叉子first.Lock()second.Lock()// 进餐fmt.Printf("哲学家 %d 开始进餐 (第%d次)\n", p.id, p.eatingTimes+1)time.Sleep(time.Second * 1)p.eatingTimes++// 释放叉子second.Unlock()first.Unlock()
}func (p *Philosopher) dine(sem chan struct{}, wg *sync.WaitGroup) {defer wg.Done()for i := 0; i < 3; i++ { // 每个哲学家吃3次便于观察p.think()// 获取就餐许可sem <- struct{}{}p.eat()<-sem}
}func main() {// 初始化叉子forks := make([]*sync.Mutex, numPhilosophers)for i := range forks {forks[i] = &sync.Mutex{}}// 创建哲学家philosophers := make([]*Philosopher, numPhilosophers)for i := range philosophers {philosophers[i] = &Philosopher{id:        i,leftFork:  forks[i],rightFork: forks[(i+1)%numPhilosophers],}}// 使用信号量限制同时就餐人数(最多允许4人同时尝试拿叉子)sem := make(chan struct{}, numPhilosophers-1)var wg sync.WaitGroup// 开始就餐for _, p := range philosophers {wg.Add(1)go p.dine(sem, &wg)}wg.Wait()// 统计每位哲学家就餐次数for _, p := range philosophers {fmt.Printf("哲学家 %d 总共进餐 %d 次\n", p.id, p.eatingTimes)}
}
http://www.xdnf.cn/news/12910.html

相关文章:

  • Java 中字节流的使用详解
  • 用 AI 开发 AI:原汤化原食的 MCP 桌面客户端
  • UDP连接套接字与异步Socket通道详解
  • Java核心技术-卷I-读书笔记(第十二版)
  • ESP12E/F 参数对比
  • 单线程模型中消息机制解析
  • Map 接口
  • 【学习笔记】0-RTT
  • 强化学习入门:交叉熵方法数学推导
  • 支付系统架构图
  • 算法-构造题
  • 嵌入式学习--江协stm32day4
  • 哈佛总线架构是什么?
  • 随机访问介质访问控制:网络中的“自由竞争”艺术
  • stm32_LAN8720驱动
  • atc abc409E
  • 【Vue3】(三)vue3中的pinia状态管理、组件通信
  • Linux--vsFTP配置篇
  • HNCTF 2025 Just Ping Write-up
  • 基于安卓的文件管理器程序开发研究源码数据库文档
  • 分类数据集 - 垃圾分类数据集下载
  • 19-Oracle 23 ai Database Sharding-知识准备
  • ffmpeg(四):滤镜命令
  • C++ 搜索二叉树(BST)详解:实现与应用
  • 从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(十二)
  • DeepSeek10-RAG相关模型知识说明
  • Vue入门到实战之第一篇【超基础】
  • SeaweedFS S3 Spring Boot Starter
  • 三十五、面向对象底层逻辑-Spring MVC中AbstractXlsxStreamingView的设计
  • 网络编程(TCP编程)