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.pswp.cn/web/83368.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ateⅹⅰt()的用法

在C/C++中, atexit() 函数用于注册程序退出时需要调用的函数,即使程序通过 main() 函数返回、 exit() 函数退出或异常终止,这些注册的函数也会被执行。以下是其详细用法: 1. 函数原型与头文件 #include <cstdlib> // C++中需包含此头文件 int atexit(void (*functio…

【大模型】 使用llama.cpp 进行模型转换和量化

目录 1 相关知识 ■llama.cpp ■GGUF 格式 ■量化 2 详细步骤 克隆 llama.cpp 仓库 安装依赖 配置 CMake 构建 构建项目 验证安装 转换 safetensors 为 FP16 GGUF 量化模型 (Q4_K_M) 测试量化模型 1 相关知识 ■llama.cpp llama.cpp是一个开源的 C/C++ 库,旨…

大数据学习(133)-Hive数据分析2

​​​​&#x1f34b;&#x1f34b;大数据学习&#x1f34b;&#x1f34b; &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 用力所能及&#xff0c;改变世界。 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4…

IDEA 连接 Docker 一键打镜像

首先&#xff0c;检查 IDEA 是否安装了 Docker 插件&#xff1a; 版本比较新的 IDEA 默认都安装了这个插件&#xff0c;如果没有安装&#xff0c;安装一下。 确保我们虚拟机上安装了 Docker 和 Docker-compose&#xff0c;并启动了 Docker。 找到 IDEA 下方的 Services tab 栏…

第六讲——一元函数微分学的应用之中值定理、微分等式与微分不等式

文章目录 连续函数性质定理定理1 有界与最值定理定理2 介值定理定理3 平均值定理定理4 零点定理定理5 费马定理导数介值定理(达布定理) 中值定理罗尔定理拉格朗日中值定理柯西中值定理泰勒公式 讨论方程的根问题——微分等式证明不等式问题使用函数的性质(单调性、凹凸性、最值…

2025.06.11【Ribo-seq】|用CPAT预测sORF序列的编码潜能

文章目录 前言一、准备工作1. 安装CPAT2. 下载物种特异性模型 二、准备sORF核酸序列1. 获取sORF的拼接核酸序列示例脚本&#xff08;假设已获得外显子fasta&#xff09;&#xff1a; 三、运行CPAT预测编码潜能1. 准备CPAT模型和hexamer表2. 运行CPAT 四、结果解读五、常见问题与…

Hive面试题汇总

一、hive架构相关 遇到这类问题&#xff0c;可以灵活的去回答&#xff0c;比如可以结合平时使用hive的经验作答&#xff0c;也可以结合下图从数据的读入、解析、元数据的管理&#xff0c;数据的存储等角度回答&#xff1a; 二、hive的特点 本题主要为了考察对hive的整体使用…

树莓派超全系列教程文档--(57)如何设置 Apache web 服务器

如何设置 Apache web 服务器 设置 Apache web 服务器安装 Apache测试 web 服务器更改默认网页 为 Apache 安装 PHP 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 设置 Apache web 服务器 Apache 是一款流行的 web 服务器应用程序&#xff0c;您…

(九)现代循环神经网络(RNN):从注意力增强到神经架构搜索的深度学习演进

现代循环神经网络的内容&#xff0c;将介绍几种先进的循环神经网络架构&#xff0c;包括门控循环单元&#xff08;GRU&#xff09;、长短期记忆网络&#xff08;LSTM&#xff09;的变体&#xff0c;以及注意力机制等。这些内容将帮助你更深入地理解循环神经网络的发展和应用。 …

牛市与熊市:市场周期的双面镜

牛市推动资产增值与风险积累&#xff0c;熊市挤压泡沫并孕育机会&#xff0c;两者交替循环&#xff0c;构成市场自我调节机制。 1、概念对比&#xff1a;情绪与趋势的博弈 牛市&#xff08;Bull Market&#xff09;&#xff1a;指资产价格持续上涨&#xff08;通常涨幅超20%&a…

web程序设计期末复习-填空题

常用标签 块级标记 行内标记等 一、块级元素 特点&#xff1a; 独占一行可以设置宽度、高度、内外边距默认情况下会从上到下垂直排列 常见标签&#xff1a; 标签 含义 <div> 最常用的通用块级容器 <p> 段落 <h1>到<h6> 标题&#xff08;一级…

go全局配置redis,全局只需要连接一次,然后全局可以引用使用

创建redis文件夹、创建dadeRedis.go package redisimport ("context""github.com/go-redis/redis/v8""log""time" )var (client *redis.Clientctx context.Background() )// 初始化Redis连接&#xff08;建议在程序启动时调用&am…

缓冲区(C语言缓冲区+内核缓冲区)一个例子解释他们的关系和作用!!!

首先提出问题&#xff1a; 为什么以下代码是先sleep三秒后&#xff0c;屏幕才显示"XXXXXXX"。 #include<stdio.h> #include<unistd.h>int main() {printf("XXXXXXX");sleep(3);return 0; } 为什么以下代码是先显示"XXXXXXX"&#xf…

【2025版】Java 工程师学习路线图 —— 掌握程度描述版

✅【2025版】Java 工程师学习路线图 &#x1f4a1; 目标&#xff1a;成为合格的 Java 工程师&#xff08;前后端都要会&#xff09; &#x1f4dd; 结构清晰 | 阶段明确 | 掌握程度分级 | 适合自学或转行 &#x1f539; 阶段一&#xff1a;编程基础 计算机通识 模块内容推荐掌…

从零实现一个红队智能体

从零实现一个红队智能体(持续更新) 2025-06-09 背景&#xff1a;最近学了基础些东西和工具基础使用&#xff0c;发现一套流程下来太多需要手工要做的&#xff0c;就像自己能不能结合自己的技术栈实现小工具 &#x1f947; 第一步&#xff1a;从实用性开始分析 目标场景 希望…

Uniapp实现多选下拉框

文章目录 前言一、效果展示1.1 下拉效果图1.2 下拉选择效果图1.3 选择显示效果图 二、组件源码2.1.CustomCheckbox.vue源码2.2.niceui-popup-select.vue源码 三、demo.vue代码演示 前言 之前在使用Uniapp时&#xff0c;一直都是下拉框单选。今天某个项目需求需要使用Uniapp实现…

JavaScript-Array.from

Array.from() 是 JavaScript 中用于将类数组对象&#xff08;array-like&#xff09;或可迭代对象&#xff08;iterable&#xff09;转换为真实数组的一个非常有用的方法。 &#x1f4cc; 一、基本语法 Array.from(arrayLike, mapFn?, thisArg?)参数说明&#xff1a; 参数类…

二刷苍穹外卖 day02

新增员工 DTO 将前端传递的参数列表通过对应的实体类接收 当前端提交的数据和实体类中对应的属性差别较大时&#xff0c;使用DTO来封装数据 Data public class EmployeeDTO implements Serializable {private Long id;private String username;private String name;private…

通过Heron Handoff 插件我们在figma设计中可以像sketch导出离线标注

一、设计交付的历史困境与破局契机 在数字产品开发的全流程中&#xff0c;设计标注的高效传递始终是连接创意与实现的关键纽带。传统设计工具如 Sketch 凭借 Bluebeam、Sketch Measure 等插件构建了成熟的离线标注体系&#xff0c;设计师可将标注文件打包交付&#xff0c;开发…

SSE 数据的传输无法流式获取

问题 调试过程中发现SSE数据返回的时间都是一样的&#xff0c;怀疑是接口问题。 参考 EventSource数据一次性出来&#xff0c;并未流式输出的原因_sourceevent为什么结果一下全部返回了-CSDN博客 处理 EventStream 不能流式返回的问题&#xff1a;Nginx 配置优化 解决方案 …