#### 两个例子
.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. CentOS7更改网卡名称为eth0

    #!/bin/bash # Author: fansik # Date: 2017年 09月 19日 星期二 :: CST sed -i 's@rhgb@rhgb net.ifnames=0@g' / ...

  2. 玩转git版本控制软件

    一.git的基本介绍 1.什么是git? git是个开源的分布式版本控制软件,用以有效.高速的处理从很小到非常大的项目版本管理.说白了就是个版本控制软件 2.git的使用方法 git软件是通过命令来实 ...

  3. Android开发问题:ActivityNotFoundException: Unable to find explicit activity class

    http://blog.csdn.net/debuglog/article/details/7236013 原因:AndroidManifest.xml未添加对应Activity配置. 解决办法:在A ...

  4. 序列化+protobuff+redis

    背景: 当redis里面需要存储 “key-字符串,value-对象” 时,是不能直接存对象,而是需要将序列化后的对象存进redis. redis没有实现内部序列化对象的功能,所以需要自己提前序列化对 ...

  5. Tensorflow学习笔记(1)--安装

    安装 1.ubuntu 14.04 2. 清华大学开源软件镜像站:https://mirrors.tuna.tsinghua.edu.cn/help/tensorflow/ (要求sudo权限,如果报 ...

  6. 使用CoreData存储数据

    - (void)viewDidLoad { [super viewDidLoad]; //获取模型文件的路径 NSString *path=[[NSBundle mainBundle]pathForR ...

  7. 每天一个Linux命令(59)wget命令

        wget命令用来从指定的URL下载文件.     (1)用法:     用法:  wget  [参数]  [URL]     (2)功能:     功能:  wget命令用来从指定的URL下载 ...

  8. Android开发BUG及解决方法

    错误描述 问题1: 按照提示打开gradle-wrapper.properties文件 并且将gradle-2.8-all.zip改为gradle-2.10-all.zip,重新导入项目 问题2: 却 ...

  9. Python编程-数据类型方法

    一.进制简介 进制也就是进位制,是人们规定的一种进位方法.对于任何一种进制---X进制,就表示某一位置上的数运算时是逢X进一位.十进制是逢十进一,十六进制是逢十六进一,二进制就是逢二进一,以此类推,x ...

  10. 理解$watch、$apply与$digest

    Angular环境 浏览器里面有一个事件队列(event queue),用户触发啥事儿,或者网络请求,延时操作(例如定时器之类),都是一个event,浏览器会轮询这些事件,然后调用这些回调(这里的回调 ...