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

关于Ai问答的ET7.2框架协程锁解读记录

锁的核心机制

1. 整体架构

CoroutineLockComponent (全局单例)↓
Dictionary<锁类型, CoroutineLockQueueType>↓
CoroutineLockQueueType 管理多个 CoroutineLockQueue↓
CoroutineLockQueue 管理具体某个键的等待队列

2. 为什么要用 HashCode?

// 使用场景示例
public async ETTask UpdatePlayerData(Player player)
{// key 通常是实体ID或特定对象的HashCodeusing (await CoroutineLockComponent.Instance.Wait(CoroutineLockType.Player, player.Id)){// 临界区}
}

使用 HashCode/ID 的原因:

  • 细粒度锁:不是锁整个类型,而是锁特定对象
  • 避免冲突:不同玩家的操作可以并发,同玩家操作才需要互斥
  • 资源标识:通过key标识具体的资源(玩家、物品、邮件等)

3. 锁的实现原理 - 通过队列等待

public async ETTask<CoroutineLock> Wait(int time)
{// 情况1:当前没有锁,直接获取if (this.currentCoroutineLock == null){this.currentCoroutineLock = CoroutineLock.Create(type, key, 1);return this.currentCoroutineLock;}// 情况2:已有锁在占用,进入等待队列WaitCoroutineLock waitCoroutineLock = WaitCoroutineLock.Create();this.queue.Enqueue(waitCoroutineLock);  // 关键:加入等待队列// 设置超时定时器if (time > 0){long tillTime = TimeHelper.ClientFrameTime() + time;TimerComponent.Instance.NewOnceTimer(tillTime, TimerCoreInvokeType.CoroutineTimeout, waitCoroutineLock);}// 等待直到被唤醒或超时this.currentCoroutineLock = await waitCoroutineLock.Wait();return this.currentCoroutineLock;
}

定时器的作用

1. 超时机制

// 默认60秒超时
if (time > 0)  // time = 60000
{long tillTime = TimeHelper.ClientFrameTime() + time;TimerComponent.Instance.NewOnceTimer(tillTime, TimerCoreInvokeType.CoroutineTimeout, waitCoroutineLock);
}

是的,你的理解正确:

  • NewOnceTimer 在指定时间后执行一次
  • 60秒后如果锁还没获取到,会触发超时
  • 防止死锁:避免协程永远等待

2. 完整流程示例

假设有3个协程要获取同一个锁:

// 协程A、B、C都要操作同一个玩家
var taskA = UpdatePlayerData(playerId);
var taskB = UpdatePlayerData(playerId); 
var taskC = UpdatePlayerData(playerId);

执行过程:

时间线:
0ms: 协程A调用Wait() → currentCoroutineLock为null → 立即获得锁CoroutineLockQueue: [协程A持有锁]10ms: 协程B调用Wait() → 有锁在占用 → 创建WaitCoroutineLock加入队列CoroutineLockQueue: [协程A持有锁] → [协程B等待]20ms: 协程C调用Wait() → 有锁在占用 → 创建WaitCoroutineLock加入队列  CoroutineLockQueue: [协程A持有锁] → [协程B等待] → [协程C等待]100ms: 协程A释放锁(Dispose) → 唤醒协程BCoroutineLockQueue: [协程B持有锁] → [协程C等待]200ms: 协程B释放锁 → 唤醒协程CCoroutineLockQueue: [协程C持有锁]

关键设计点

1. 队列管理锁

// 不是通过内存地址锁,而是通过队列顺序
this.queue.Enqueue(waitCoroutineLock);  // 进入等待队列
await waitCoroutineLock.Wait();         // 等待被唤醒

2. 超时保护

// 60秒后自动超时,避免永久等待
TimerComponent.Instance.NewOnceTimer(tillTime, TimerCoreInvokeType.CoroutineTimeout, waitCoroutineLock);

3. 链式唤醒

当一个锁释放时,会自动唤醒队列中的下一个等待者。

总结

这个锁机制的核心是:通过队列管理协程的执行顺序,而不是真正的"锁定"内存

  • HashCode:标识要保护的具体资源
  • 队列:管理等待顺序
  • 定时器:提供超时保护
  • 异步等待:协程挂起而不是线程阻塞

这样设计的优点是可以在异步环境中安全地控制并发,避免竞态条件,同时保持高性能。

提问

也就是说哪个协程能通过Wait方法返回CoroutineLock类型的 currentCoroutineLock,这个协程就是正在锁中执行逻辑,其他想要操作此内存的协程则会进入等待队列进行排队,等待时间默认是1分钟防止一直等下去对吗

回答

完全正确! 你的理解非常准确。

锁机制的核心逻辑

获取锁的流程

// 成功获取锁的协程
using (var lock = await CoroutineLockComponent.Instance.Wait(type, key))
{// 这个协程现在"持有锁"// 可以安全地执行临界区代码await ModifySharedData();
} // 离开using块时自动释放锁

具体执行过程

第一个协程:

// currentCoroutineLock == null,直接获得锁
this.currentCoroutineLock = CoroutineLock.Create(type, key, 1);
return this.currentCoroutineLock; // 立即返回,进入临界区

后续协程:

// currentCoroutineLock != null,进入等待队列
WaitCoroutineLock waitCoroutineLock = WaitCoroutineLock.Create();
this.queue.Enqueue(waitCoroutineLock); // 排队
this.currentCoroutineLock = await waitCoroutineLock.Wait(); // 挂起等待

等待队列示意图

CoroutineLockQueue 状态变化:初始状态: [锁空闲] currentCoroutineLock = null协程A进入: [A持有锁] currentCoroutineLock = A的锁queue = []协程B进入: [A持有锁] → [B等待] currentCoroutineLock = A的锁  queue = [B的等待器]协程C进入: [A持有锁] → [B等待] → [C等待] queue = [B的等待器, C的等待器]A释放锁: [B持有锁] → [C等待] queue = [C的等待器]currentCoroutineLock = B的锁B释放锁: [C持有锁]queue = []currentCoroutineLock = C的锁

超时保护机制

你的理解完全正确:

  • 默认60秒:防止协程无限期等待
  • 超时后果:等待的协程会在60秒后收到超时通知,从等待状态退出
  • 避免死锁:如果某个协程持有锁但发生异常没有释放,其他等待者不会永远卡住
// 超时设置
if (time > 0) // time = 60000 (60秒)
{long tillTime = TimeHelper.ClientFrameTime() + time;TimerComponent.Instance.NewOnceTimer(tillTime, TimerCoreInvokeType.CoroutineTimeout, waitCoroutineLock);
}

实际使用示例

public async ETTask SafeUpdatePlayerGold(long playerId, int goldChange)
{// 只有成功通过Wait返回的协程才能执行后续代码using (await CoroutineLockComponent.Instance.Wait(CoroutineLockType.Player, playerId)){// 这个协程现在"持有玩家锁"Player player = GetPlayer(playerId);player.Gold += goldChange;await SaveToDatabase(player);// 在using块结束前,其他想要操作同一玩家的协程都在排队等待}// 释放锁,唤醒队列中的下一个等待者
}

总结

你的理解完全正确:

  1. 谁能执行:通过Wait方法成功返回CoroutineLock的协程获得执行权
  2. 其他协程:进入等待队列排队
  3. 超时保护:默认60秒防止永久等待
  4. 顺序执行:队列确保同一资源的操作按顺序执行,避免竞态条件

这就是ET框架中协程锁的精髓——通过异步队列管理来实现安全的并发控制。

http://www.dtcms.com/a/578720.html

相关文章:

  • 项目设计文档【示例】
  • Linux应用开发-11-消息队列
  • 基于遗传算法与非线性规划的混合优化算法在电力系统最优潮流中的实现
  • 高动态范围(HDR)图像文件格式OpenEXRLinux开发库介绍
  • 在门户网站做产品seowordpress主题英文改中文版
  • 百度助手手机下载网站链接优化
  • 商标注册查询官网网站wordpress怎么截图直接粘贴
  • 网站建设价格与方案如何让百度口碑收录自己的网站
  • 大模型原理之深度学习与神经网络入门
  • 学习前端记录(二)21-40
  • 电源完整性08-电容网络配置方法
  • 可以做防盗水印的网站山东手机版建站系统信息
  • 专门做音箱的网站浙江信息网查询系统
  • 论需求分析方法及应用
  • 网站顶部菜单下拉固定宜宾市珙县住房城乡建设网站
  • 青少年机器人技术等级考试理论综合试卷(一级)2018年9月
  • Windows状态栏时间显示到秒的设置方法
  • 企业做网站推广产品需要多少钱标志设计公司成都
  • 网站的建设与应用上海企业网站建设服务
  • Chrome Edge 最新DNS泄露检测方法+指纹解析步骤(含工具)
  • 网站平台建设公司网站下拉菜单代码
  • stack、queue和priority_queue(容器适配器、仿函数的使用)
  • 鄂州网站seo意见反馈的网站怎么做
  • 四元数 (Quaternion)中的扰动知识(6)
  • 代刷网站建设青海省建设厅官方网站建设云
  • 南山网站优化建设网站安全措施
  • 推动品牌建设的网站网络宣传方案
  • 图片类网站如何做优化WordPress众筹源码
  • 电影网站是怎么做的陕西做天然气公司网站
  • 从零开始MySQL-第5章 函数