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

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

相关文章:

  • 数据库学习(三)——MySQL锁
  • Ubuntu20.04中MySQL的安装和配置
  • 基于React 的 AntD 库进行前端开发过程中的问题汇总
  • 使用 C/C++的OpenCV 实时播放火柴人爱心舞蹈动画
  • 机器人/智能车纯视觉巡线经典策略—滑动窗口+直方图法
  • 神经网络-Day48
  • 【CBAP50技术手册】#39 Roles and Permissions Matrix(角色与权限矩阵):业务分析师的“秩序守护器”
  • AU音频软件|Audition 2025网盘下载与安装教程指南
  • 华为开源自研AI框架昇思MindSpore应用案例:ICT实现图像修复
  • 算法:位运算
  • Linux 内存管理调试分析:ftrace、perf、crash 的系统化使用
  • 从零开始的云计算生活——番外,实战脚本。
  • OpenEuler服务器警告邮件自动化发送:原理、配置与安全实践
  • ElGamal加密算法:离散对数难题的安全基石
  • 【大模型】【推荐系统】LLM在推荐系统中的应用价值
  • Linux nano命令的基本使用
  • Java安全点safepoint
  • Fractal Generative Models论文阅读笔记与代码分析
  • C# 表达式和运算符(表达式和字面量)
  • Go基本语法——go语言中的四种变量定义方法
  • 陕西省交通建设集团西长分公司网站/外贸接单平台哪个最好
  • 杭州网站建设q479185700惠/百度一下搜索网页
  • 建设网站以后怎么让百度收录呢/工作手机
  • 广东智慧团建系统登录入口/宁波seo网络推广公司排名
  • react wordpress 知乎/营销排名seo
  • 大型企业网站开发/aso优化软件