2009年4月3日星期五
Nebula3基础层-App
2009年4月2日星期四
2009年3月31日星期二
Nebula3基础层-消息子系统

Message子系统是Nebula3实现多线程架构的核心。
Port:1.消息接收端口。消息被立即处理并且程序将被阻塞直到消息处理完成。消息是通过增加到Port中的Handler来处理的,Port可以增加一个或多个Handler。当接收到一个消息,增加到Port中的每个Handler将被调用来处理消息,直到有一个Handler处理完消息后返回true,这意味着消息处理完成了。
2.Port::RegisterMessage(const Id& msgId)方法用来注册该Port能处理的消息类型。
AsyncPort:在一个分开的线程中调用handlers来处理消息,因此不会阻塞主线程。AsyncPort的子类覆写AsyncPort::OnCreateHandlers()方法,在这个方法中创建Handler并把它添加到AsyncPort中。
Handler:实际处理消息的类。用户需要继承Handler类并覆写Handler::HandleMessage()方法。
Id:消息类型标识符。在消息中使用DeclareMsgId和ImplementMsgId宏来实现。
Message:包装数据并可以被发送到Port和AsyncPort。这实现了一个通用的通信机制,不仅可以用于相同线程,线程之间,甚至还可以用在不同机器之间的通讯。Message作为一个普通的C++对象,可以被持久化。用户继承Message类实现自己需要的不同消息。
Dispatcher:是一个特殊的消息接收端口。Dispatcher把消息分发到能处理该消息的端口上。具体实现可以参考类图和以下图示:
Nebula3基础层-线程子系统

线程子系统主要是对各种平台的多线程部分进行抽象和封装。
Thread:对平台线程的封装,调用Thread::Start()开启一个新的线程。用户需要在子类覆写Thread::DoWork()方法来执行自己需要的操作,当用户需要在子类的DoWork()方法中执行循环操作时就必须调用Thread::ThreadStopRequested()方法来判断线程是否停止。调用Thread::Stop()停止一个线程,线程会等待DoWork()方法处理完成后才退出。
Event:用来处理线程同步。当一个线程调用Event::Wait()时,线程将处于等待状态。调用Event::Signal()将激活一个等待的线程。Event::Peek()用来检查线程当前的状态,并立即返回结果。
CriticalSection:同步代码块,处于CriticalSection::Enter()和CriticalSection::Leave()之间的代码,同时只能由一个线程来执行。
Interlocked:提供一些简单的原子操作。
2009年3月30日星期一
Nebula3基础层-IO子系统
2009年3月6日星期五
Lua程序设计 第九章 协同程序
2.线程与协同程序的主要区别在于,一个具有多线程的程序可以同时运行几个线程,而协同程序却需要彼此协作地运行。就是说,一个具有多个协同程序的程序在任何时刻只能运行一个协同程序,并且正在运行的协同程序只会在其显示地挂起时,它的执行才会暂停。
3.当一个协同程序A唤醒另一个协同程序B,协同程序A就处于一个特殊状态,既不是挂起状态(无法继续A的执行),也不是运行状态(B在运行)。所以将这时的状态称为“正常”状态。
4.Lua提供的是一种“非对称的协同程序(asymmetric coroutine)”。也就是说,Lua提供了两个函数来控制协同程序的执行,一个用于挂起执行,另一个用于恢复执行。而一些其它的语言则提供了“对称的协同程序(symmetric coroutine)“,其中只有一个函数用于转让协同程序之间的执行权。
Lua程序设计 第八章 编译,执行与错误
2.Lua提供的所有关于动态库的功能都聚集在一个函数中,即package.loadlib。
3.由于Lua是一种扩展语言,通常嵌入到应用程序中,因此在发生错误时不能简单地崩溃或退出。相反,只要发生一个错误,Lua就应该结束当前程序块并返回应用程序。
4.对于大多数应用程序而言,无须在Lua代码中作任何错误处理,应用程序本身会负责这类问题。
2009年3月5日星期四
Lua程序设计 第六章 深入函数
2.函数存储在table字段中可以支持许多Lua的高级应用,例如:模块和面向对象编程。
3.若将一个函数写在另一个函数中,那么这个位于内部的函数便可以访问外部函数中的局部变量,这项特性称之为“词法域”。
4.函数不仅可以存储在全局变量中,还可以存储在table的字段中和局部变量中。
5.Lua函数支持“尾调用消除(tail-call elimination)”。所谓“尾调用”就是一种类似goto的函数调用。当一个函数调用是另一个函数的最后一个动作,该调用才算是一条“尾调用”。在进行“尾调用”时不耗费任何栈空间。
Lua程序设计 第五章 函数
2.一个函数若只有一个参数,并且此参数是一个字符串或table构造式,那么圆括号便可有可无。
3.调用时提供的实参数量可以与形式参数数量不同。Lua会自动调整实参的数量,以匹配参数表的要求。原则是:若实参多于形参,则舍去多于的实参;若实参不足,则多余的形参初始化为nil。
4.Lua允许函数返回多个结果。
5.return后面的内容是不需要圆括号的。在该位置上书写圆括号会导致不同的行为。例如:return(f(x)),将只返回一个值,而无关f返回几个值。
6.Lua中的函数还可以接受不同数量的参数。
7.Lua用...参数表式函数可以接受不同数量的实参。
8.Lua中的参数传递机制是具有“位置性”的,但有时通过名称来指定实参也是很有用的。
2009年3月3日星期二
Lua程序设计 第四章 语句
2.Lua用local语句来创建局部变量。
3.尽可能地使用局部变量,局部变量可以避免将一些无用的名称引入全局环境,避免搞乱了全局环境。
4.在需要时才声明变量,可以使这个变量在初始化时刻就拥有一个有意义的初值,缩短变量的作用域有助于提高代码的可读性。
Lua程序设计 第三章 表达式
2.关系运算符:“<”(小于),“>”(大于),“<=”(小于等于),“>=”(大于等于),“==”(相等性测试),“~=”(不等性测试)
3.逻辑操作符:and,or,not
4.Lua中使用操作符“..”(两个点)连接两个字符串。
5.构造式是用于创建和初始化table的表达式。
2009年3月2日星期一
Lua程序设计 第二章 类型与值
2.Lua能够高效处理长字符串,在Lua程序中操作100k或1M的字符串是很常见的。
3.Lua提供运行时的数字与字符串的自动转化,但到现在还不能确定在Lua的设计中,这些自动转化是否是算一项好的设计,建议最好不要依赖它们。
4.定义a为table,a.x和a[x]是不同的,前者表示a["x"],以字符串"x"来索引table。而或者是以变量x的值来索引table。
5.就Lua习惯而言,数组通常以1作为索引的起始值。
6.在Lua中,函数是作为“第一类值”来看待的。这表式函数可以存储在变量中,可以通过参数传递给其它函数,还可以作为其它函数的返回值。
7.userdata用于表式一种由应用程序或C语言库所创建的新类型。
2009年3月1日星期日
2009年2月28日星期六
2009年2月26日星期四
Generating Shaders From HLSL Fragments
Shaders are cool. You can do all sorts of interesting things with them: this and previous ShaderX books are full of examples. Alongside their power, however, programmable shaders can lead to an explosion of permutations: my last Xbox game contained 89 different pixel shaders, and my current project already has far more. Many of these shaders are variations on a few basic themes, for instance level-of-detail approximations of a material, or the same lighting model both with and without animation skinning. The total number of combinations is huge and is increasing all the time. Typing everything out by hand would be time consuming, error prone, and a maintenance nightmare.
This article will describe how to automatically generate large numbers of shader permutations from a smaller set of handwritten input fragments.
2009年2月23日星期一
Nebula3的点和向量
点:
点+向量=点
点-向量=点
点-点=向量
向量:
向量+向量=向量
向量-向量=向量
向量*常量=向量
Nebula3使用的一些关键字
在VC++中可使用另一关键字_forceinline 代替inline 关键字.这个关键字将命令编译器跳过一般的ROI 分析(Return On Investment --一种编程缩略语),将所对应的代码强行内联.在有写时候,编译器会拒绝将一个函数内联,使用这个关键字,用户只得到一个编译警告,就可强行内联.
在使用内联函数时,是由编译器决定它们是按普通函数处理还是将调用函数部分用实际的函数体代码替换。不允许将递归函数进行内联(VC++可进行编译器选项设置,允许内联扩展到一定深度)
下面情况不宜使用内联:
1.如果函数体内的代码比较长,使用内联将导致内存消耗代价较高。
2.如果函数体内出现循环,那么执行函数体内代码的时间要比函数调用的开销大。
volatile:
如果将将变量加上volatile修饰,则编译器保证对此变量的读写操作都不会被优化。
一般说来,volatile用在如下的几个地方:
1、中断服务程序中修改的供其它程序检测的变量需要加volatile。
2、多任务环境下各任务间共享的标志应该加volatile。
3、存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能有不同意义。
__cdecl:
C,C++的默认调用规范,参数从右到左传替,由调用函数管理堆栈。
2009年2月19日星期四
Nebula3单例
可以通过静态的Instance()方法获得单例对象,该方法返回单例类的单一实例。保证返回的指针是有效的。在Instance()方法被调用时候如果单例对象不存在,那么将抛出一个断言。
// obtain a pointer to the Core::Server singleton
Ptr
你也可以检查给定的单例是否存在:
// does the Core::Server object exist?
if (Core::Server::HasInstance())
{
// yep, the core server exists
}
Nebula3提供了一些宏帮助实现单例类:
// declare a singleton class
class MySingletonClass : public Core::RefCounted
{
DeclareClass(MySingletonClass);
DeclareSingleton(MySingletonClass);
public:
/// constructor
MySingletonClass();
/// destructor
virtual ~MySingletonClass();
...
};
// implement the singleton class
ImplementClass(MyNamespace::MySingletonClass, 'MYSC', Core::RefCounted);
ImplementSingleton(MyNamespace::MySingletonClass);
//------------------------------------------------------------------------------
/**
Implements the Singleton constructor.
*/
MySingletonClass::MySingletonClass()
{
ConstructSingleton;
}
//------------------------------------------------------------------------------
/**
Implements the Singleton destructor.
*/
MySingletonClass:~MySingletonClass()
{
DestructSingleton;
}
DeclareSingleton()和ImplementSingleton()宏跟DeclareClass()和ImplementClass()宏相似。它们往类里增加了一些静态方法(Instance()和HasInstance()方法)。类的构造函数和析构函数必须包含ConstructSingleton和DestructSingleton宏。ConstructSingleton宏初始化一个私有的静态单例指针并确定这个类没有其它的实例存在(否则,将抛出一个断言)。DestructSingleton宏让静态单例指针无效。
默认是从本地线程获取一个单例。这意味着单例是创建在Nebula3应用程序的一个线程中,并且其它线程不能访问该单例。这种方式遵循着“并行Nebula”的设计,让多线程编程变得更加简单。隐藏在“并行Nebula3”背后的构想是,一个典型的Nebula3应用程序包含一些运行在分开的CPU核上的“胖线程”("Fat Threads")。胖线程实现例如异步IO,渲染,物理等等。每一个胖线程初始化它自己的Nebula3运行库,这个库包含胖线程执行特定任务所需的最小Nebula3环境。这基本上消除了大部分Nebula3代码所需的细粒度同步,并且把“线程相关”的代码集中在几个定义明确的范围内用于胖线程之间的通讯。“并行Nebulas”设计的另外一个有用效果是,让程序员不必太关注代码运行在一个多线程环境。典型的Nebula3代码就像普通的单线程代码,然而它可以运行在它自己的胖线程内。
原文:
[声明]:限于译者水平,文中难免错漏之处,欢迎各位网友批评指正;


