#### 两个例子
.GUI event loop ```
while (running)
{
// 从事件队列里获取一个事件
Event event = getNextEvent();
// Handle event...
}
```
.Central event bus
不同系统公用的通信中心 #### 有问题的code ```
class Audio
{
public:
static void playSound(SoundId id, int volume);
}; class Audio
{
public:
static void playSound(SoundId id, int volume);
}; class Menu
{
public:
void onSelect(int index)
{
Audio::playSound(SOUND_BLOOP, VOL_MAX);
// Other stuff...
}
}; ```
问题: . api同步调用, 阻塞到audio处理完请求
. 多个请求不能合并处理
. 处理请求有可能运行在错误的线程上(没有锁) ####模式定义:
```
一系列的通知或请求存储在先进先出的队列里. 发送通知进行入队; 请求处理者从队列里获取请求.
``` ##### 何时使用
```
.如果只是想从sender那里获取消息,使用 observer 或者command将会更简单.
.当你需要push什么到另一个模块,或者pull什么从另一个地方的时候, 你需要一个buffer, 此时就需要一个队列了.
. 队里提供的pull操作, receiver可以延迟处理,合并请求, 或者丢弃. pull请求不开放给sender使用,当sender需要获得响应的时候,队列就有点技穷了.(send then pray)
``` #### 注意事项
```
.中心事件队列是个全局变量
.世界状态会改变,(队列处理不是及时的)
.困在反馈循环里(a ->b -> a ->b ...).如果是同步队列的,你会很快的发现循环bug.
一般原则: 避免在在处理事件的函数里发送事件.
``` #### Sample Code ```
struct PlayMessage
{
SoundId id;
int volume;
}; class Audio
{
public:
static void init()
{
numPending_ = ;
} // Other stuff...
private:
static const int MAX_PENDING = ; static PlayMessage pending_[MAX_PENDING];
static int numPending_;
}; void Audio::playSound(SoundId id, int volume)
{
assert(numPending_ < MAX_PENDING); pending_[numPending_].id = id;
pending_[numPending_].volume = volume;
numPending_++;
} class Audio
{
public:
static void update()
{
for (int i = ; i < numPending_; i++)
{
ResourceId resource = loadSound(pending_[i].id);
int channel = findOpenChannel();
if (channel == -) return;
startSound(resource, channel, pending_[i].volume);
} numPending_ = ;
} // Other stuff...
}; ``` ##### ring buffer 循环buffer ```
class Audio
{
public:
static void init()
{
head_ = ;
tail_ = ;
} // Methods...
private:
static int head_;
static int tail_; // Array...
}; void Audio::playSound(SoundId id, int volume)
{
assert((tail_ + ) % MAX_PENDING != head_); // Add to the end of the list.
pending_[tail_].id = id;
pending_[tail_].volume = volume;
tail_ = (tail_ + ) % MAX_PENDING;
} void Audio::update()
{
// If there are no pending requests, do nothing.
if (head_ == tail_) return; ResourceId resource = loadSound(pending_[head_].id);
int channel = findOpenChannel();
if (channel == -) return;
startSound(resource, channel, pending_[head_].volume); head_ = (head_ + ) % MAX_PENDING;
}
``` ##### 合并请求 ```
void Audio::playSound(SoundId id, int volume)
{
// Walk the pending requests.
for (int i = head_; i != tail_;
i = (i + ) % MAX_PENDING)
{
if (pending_[i].id == id)
{
// Use the larger of the two volumes.
pending_[i].volume = max(volume, pending_[i].volume); // Don't need to enqueue.
return;
}
} // Previous code...
}
``` ##### 多线程 push pull操作需要线程安全 #### 队列里保存的是什么 ```
event or message
event queue(一对多)
描述一些已经发生的事情, 类似异步的observer模式
.允许多个监听者, 队列里保存的都是*已经发生的事件*, 发送者不关心谁去接受它.
.作用域更广.被用于广播一类的事情.趋向于全局可见.
message queue(多对一)
更趋向于只有一个监听者. 多个请求从不同的地方发来,一个处理者进行处理
``` #### 谁可以读队列 ```
单播队列:
.队列实现读取. 发送者只管发送
.队列被封装的更好
.没有读取竞争(决定是广播还是挨个分配)
广播队列:
.如果没有监听者,event被丢弃
.你可能会需要一个事件过滤
工作队列:
类似广播队列,比如worker pool
.需要调度
``` #### 谁可以写队列 ```
一个写者(类似同步observer)
.你明确知道事件是谁发出的
.通常允许多个读者
多个写者
.注意循环
.需要有访问发送者的途径(事件里包含sender的引用)
``` #### 队里里对象的生命周期 ```
. 转移所有权. 有发送者转给队列,队列转给接受者
. 共享所有权.
. 所有权只给队列. (队列申请内存,然后发送者填充数据, 接受者得到引用)
``` ###See also ```
. 队列很像是异步的observer
. message queue, pub sub
. 有限状态机, 状态机需要输入,如果你想异步执行,可以使用队列. 如果你需要多个状态机互相发消息, 需要一个queue接受输入(mail box), 这叫做actor model
. go语言内置的channel本质上就是个 事件或消息 队列.
```

15_游戏编程模式EventQueue的更多相关文章

  1. 游戏编程模式KeyNote

    [游戏编程模式KeyNote] 1.命令模式. 重做在游戏中并不常见,但重放常见.一种简单的重放实现是记录游戏每帧的状态,这样它可以回放,但那会消耗太多的内存.相反,很多游戏记录每个实体每帧运行的命令 ...

  2. 游戏编程模式 Game Programming Patterns (Robert Nystrom 著)

    第1篇 概述 第1章 架构,性能和游戏 (已看) 第2篇 再探设计模式 第2章 命令模式 (已看) 第3章 享元模式 (已看) 第4章 观察者模式 (已看) 第5章 原型模式 (已看) 第6章 单例模 ...

  3. 16_游戏编程模式ServiceLocator 服务定位

    ####简单说,就是某个系统作为一个服务,对全局系统可见. Service Locator (服务定位) ``` //简单粗暴的代码, 使用声音系统 // Use a static class? Au ...

  4. DirectX游戏编程入门

    刚开始学习D3D,安装完DirectX9后,在VS2008中新建Win32项目· ----------------------------------------------------------- ...

  5. DirectX 11游戏编程学习笔记之8: 第6章Drawing in Direct3D(在Direct3D中绘制)(习题解答)

            本文由哈利_蜘蛛侠原创,转载请注明出处.有问题欢迎联系2024958085@qq.com         注:我给的电子版是700多页,而实体书是800多页,所以我在提到相关概念的时候 ...

  6. PC游戏编程(入门篇)(前言写的很不错)

    PC游戏编程(入门篇) 第一章 基石 1. 1 BOSS登场--GAF简介 第二章 2D图形程式初体验 2.l 饮水思源--第一个"游戏"程式 2.2 知其所以然一一2D图形学基础 ...

  7. 游戏编程算法与技巧 Game Programming Algorithms and Techniques (Sanjay Madhav 著)

    http://gamealgorithms.net 第1章 游戏编程概述 (已看) 第2章 2D图形 (已看) 第3章 游戏中的线性代数 (已看) 第4章 3D图形 (已看) 第5章 游戏输入 (已看 ...

  8. 《逐梦旅程 WINDOWS游戏编程之从零开始》笔记5——Direct3D中的顶点缓存和索引缓存

    第12章 Direct3D绘制基础 1. 顶点缓存 计算机所描绘的3D图形是通过多边形网格来构成的,网网格勾勒出轮廓,然后在网格轮廓的表面上贴上相应的图片,这样就构成了一个3D模型.三角形网格是构建物 ...

  9. 3D游戏编程大师技巧──2D引擎的编译问题

    接上一篇文章,这里将介绍2D引擎的编译,从现在开始才真正进入<3D游戏编程大师技巧>的学习.本书的第一.二章只是简介了游戏编程和windows编程,从第三章开始才是介绍<window ...

随机推荐

  1. JAVA学习笔记----【转】 java.toString() ,(String),String.valueOf的区别

    在java项目的实际开发和应用中,常常需要用到将对象转为String这一基本功能.本文将对常用的转换方法进行一个总结. 常用的方法有Object#toString(),(String)要转换的对象,S ...

  2. CuteEditor.Editor+a+a+c+a+a.a() System.RuntimeType.get_Assembly() 问题解决方法

    问题: Server Error in '/' Application. Attempt by method 'CuteEditor.Editor+a+a+c+a+a.a()' to access m ...

  3. loadrunder之脚本篇——Run-time Settings之Pacing

      As soon as the previous iteration ends 前一个迭代一结束就尽可能快的开始新一轮的迭代   After the previous iteration ends ...

  4. Shell编程之while循环和until循环

    一.当型和直到型循环 1.while循环语句 while < 条件表达式 > do 指令... done while循环执行流程对应的逻辑图 2.until循环语句 until < ...

  5. char,uchar,0xff

    如果:char test = 0xFF: 此时:test != 0xFF://因为test为char类型,0xFF为int,所以编译器会将test转为int(-1),所以不等于 如果:uchar te ...

  6. Kubernetes Metrics-Server

    github地址:https://github.com/kubernetes-incubator/metrics-server 官网介绍:https://kubernetes.io/docs/task ...

  7. Kubernetes RBAC

    在Kubernetes1.6版本中新增角色访问控制机制(Role-Based Access,RBAC)让集群管理员可以针对特定使用者或服务账号的角色,进行更精确的资源访问控制.在RBAC中,权限与角色 ...

  8. Kubernetes Controller Manager

    Controller Manager 作为集群内部的管理控制中心,负责集群内的Node.Pod副本.Service Endpoint.NameSpace.ServiceAccount.Resource ...

  9. MapReduce-排序(全部排序、辅助排序)

    排序 排序是MapReduce的核心技术. 1.准备 示例:按照气温字段对天气数据集排序.由于气温字段是有符号的整数,所以不能将该字段视为Text对象并以字典顺序排序.反之,用顺序文件存储数据,其In ...

  10. DS 和【ADDRESS】学习记录

    CPU要读写一个内存单元的时候,必须先给出这个内存单元的地址. 内存单元由2部分组成. 8086CPU中,内存地址由以下组成. 1:段地址 2:偏移地址 8086CPU中,有一个DS寄存器地址,通常用 ...