unity of commanddispatchcommand 和dispatchsignal的区别

Keyboard Shortcuts?
Next menu item
Previous menu item
Previous man page
Next man page
Scroll to bottom
Scroll to top
Goto homepage
Goto search(current page)
Focus search box
Change language:
Brazilian Portuguese
Chinese (Simplified)
pcntl_signal_dispatch
pcntl_signal_dispatch & 调用等待信号的处理器
bool pcntl_signal_dispatch
成功时返回 TRUE, 或者在失败时返回 FALSE。
Example #1 pcntl_signal_dispatch() 示例
&?phpecho&"安装信号处理器...\n";pcntl_signal(SIGHUP,&&function($signo)&{&&&&&echo&"信号处理器被调用\n";});echo&"为自己生成SIGHUP信号...\n";posix_kill(posix_getpid(),&SIGHUP);echo&"分发...\n";pcntl_signal_dispatch();echo&"完成\n";?&
以上例程的输出类似于:
安装信号处理器...
为自己生成SIGHUP信号...
信号处理器被调用
- 安装一个信号处理器
- 设置或检索阻塞信号
- 等待信号
- 带超时机制的信号等待
If you are running PHP as CLI and as a "daemon" (i.e. in a loop), this function must be called in each loop& to check if new signals are waiting dispatching.
Note that calling pcntl_signal_dispatch() from within a signal handler invoked by a previous pcntl_signal_dispatch() will not trigger handlers for any new pending signals. This means that if you write a CLI daemon which forks off child processes in response to a signal, then those child processes won't be able to respond to signals. This gave me a headache for a while as pcntl_signal_dispatch() doesn't raise any errors when this occurs. One solution is to set a flag within the signal handler and react upon it (by forking off the needed child processes) elsewhere in the parent process's main loop.
Well I misspoke before. It is not enough to process signals outside of the signal handler. They must be processed outside of the tick handler (explicit or implied). So... Register a tick handler that calls pcntl_signal_dispatch();In the signal handler,In the main loop of your script, &?phpdeclare(ticks=1);global $sig_queue;global $use_queue;$sig_queue = array();$use_queue = true;&& function tick_handler(){& && pcntl_signal_dispatch();}function sig_handler($sig){& && global $sig_queue;& && global $use_queue;& && if(isset($use_queue) && $use_queue)& && {& & & & & $sig_queue[] = $sig;& && }& && else& && {& & & & & sig_helper($sig);& && }}function sig_helper($sig){& && switch($sig)& && {& && case SIGHUP:& & & & & $pid = pcntl_fork();& & & & & if($pid) print("forked $pid\n");& & & & && && default:& & & & & print("unhandled sig: $sig\n");& && }}pcntl_signal(SIGHUP,&& "sig_handler");while(true){& && if($use_queue) foreach($sig_queue as $idx=&$sig)& && {& & & & && sig_helper($sig);& & & & && unset($sig_queue[$idx]);& && }& && sleep(1);}?&
As noted by "me at subsonic dot net" calling pcntl_signal_dispatch() from within a signal handler invoked by a previous pcntl_signal_dispatch() will not trigger handlers for any new pending signals. This seems to be true even if you pcntl_exec() a new PHP processor to execute an entirely different script.The solution seems to be to explicitly call pcntl_signal_dispatch()inside a ticks_handler() . And use sig_handler(int) as a push function to a queue. Immediately following the call to dispatch in the ticks_handler, pop your queue doing what you would have done in the signal_handler until the queue is empty.&最近想项目中需要使用这个架构& 因此 上网看了很多资料摸索&& 但是对于初学者来说大多数的资料不是那么容易理解 而且文档也是英文的阅读起来有点吃力& 所以记录一下自己阅读的过程& 方便以后翻阅和跟我一样的新人学习其中也借鉴了一些前辈的资料 如有反感请联系我&& 立马进行修改& 谢谢
文档坐标 &
StrangeIoc 是依据控制反转和解耦原理设计的,支持依赖注入。
控制反转即Ioc(Inversion of Control) 它把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。所为的&控制反转&概念就是对组件对象控制权的转移,从程序代码本身转移到了内部的容器。
依赖注入(Dependency Injection)&&& 依赖注入的基本原则是:应用组件不应该负责查找资源或者其他依赖的写作对象。配置对象的工作应该由Ioc容器负责,
Bingding(绑定)
strange的核心是绑定,我们可以将一个或多个对象与另外一个或多个对象绑定(连接)在一起,将接口与类绑定来实现接口,将事件与事件接收绑定在一起。或者绑定两个类,一个类被创建时另一个类自动创建。
strange的binding由两个必要部分和一个可选部分组成,必要部分是a key and a value &key触发value,因此一个事件可以触发回调,一个类的实例化可以触发另一个类的实例化。可选部分是name,他可以区分使用相同key的两个binding 下面三种绑定方法其实都是一样的,语法不同而已
1. Bind&IRoundLogic&().To&RoundLogic&();
2. Bind(typeof(IRoundLogic)).To(typeof(RoundLogic));
3. IBinding binding = Bind&IRoundLogic&();
//使用IBinding 的时候需要引用strange.framework. 命名空间
binding.To&RoundLogic&();Bind&IRoundLogic&().To&RoundLogic&().ToName(&Logic&);    //使用非必要部分name
绑定从层次上分为
commandbinding是为了将命令绑定到方法中用的
mediationbing则是为了拦截
The injection extension(注入扩展)
在绑定扩展中最接近控制反转的思想是注入
接口本身没有实现方法,只定义类中的规则
interface ISpaceship
void input(float angle, float velocity);
IWeapon weapon{get;set;}
//使用另一个类实现这个接口,写法如下
Class Spaceship : ISpaceship
public void input(float angle, float velocity)
public IWeapon weapon{get;set;}
如果采用上面的写法,Spaceship类里面不用再写检测输入的功能了,只需要处理输入就可以了input只需要控制移动,不需要管是何种输入方式& 是手柄键盘或是其他& 只需要进行处理
也不需要武器的逻辑,仅仅是注入武器实例就可以了。但是我们需要知道武器是什么样的武器 不同的武器造成不同的掉血& 所以这块的逻辑是需要处理的
public interface IWeapon
void Attack();
public class PhaserGun : IWeapon
public void Attack(){//掉血逻辑
public class SquirtCannon : IWeapon
public void Attack(){//掉血逻辑
在ISpaceship中的代码进行一点修改
interface ISpaceship
void input(float angle, float velocity);
IWeapon weapon{get;set;}
加上Inject标签& 这样就可以进行绑定了&& 将接口与类绑定来实现接口
[Inject]标签实现接口,而不是实例化类
injectionBinder.Bind&IWeapon&().To&PhaserGun &();
injectionBinder.Bind&IWeapon&().To&PhaserGun &().ToStringleton();IWeapon weapon = PhaserGun.Get();
在绑定多个的时候就需要利用& 名称映射来进行区分
injectionBinder.Bind&ISocialService&()
.To&TwitterService&().ToSingleton()
.ToName(ServiceTypes.PRIMARY);
injectionBinder.Bind&ISocialService&()
.To&TwitterService&().ToSingleton()
.ToName(ServiceTypes.SECONDARY);
injectionBinder.Bind&ISocialService&()
.To&TwitterService&().ToSingleton()
.ToName(ServiceTypes.TERTIARY);
在[Inject]标签处 也需要进行添加名称
[Inject (ServiceTypes.TERTIARY)] //We mapped TwitterService to TERTIARY
public ISocialService socialService{get;set;}
Configuration myConfig = loadConfiguration();
injectionBinder.Bind&IConfig&().ToValue(myConfig);
具体还有几种映射就不说了& 需要的可以去看看文档
&The reflector extension(反射扩展)
List&Type& list = new List&Type& ();
list.Add (typeof(Borg));
list.Add (typeof(DeathStar));
list.Add (typeof(Galactus));
list.Add (typeof(Berserker));
//count should equal 4, verifying that all four classes were reflected.
int count = injectionBinder.Reflect (list);
反射所有已经通过injectionBinder映射的所有
injectionBinder.ReflectAll();
The dispatcher extension(调度程序扩展)
dispatcher相当于观察者模式中的公告板,允许客户监听他,并且告知当前发生的事件。在strangeioc中,通过EventDispatcher方式实现,EventDispatcher绑定触发器来触发带参数/不带参数的方法&& 触发器通常是String或枚举类型(触发器可以理解为key,或者事件的名称,名称对应着触发的方法)
如果有返回值,他将存在IEvent,一个简单的值对象包含与该事件相关的任何数据,你可以写你自己的事件满足IEvent接口,strangeioc事件叫TmEvent
如果你再使用MVCSContext 有一个全局的EventDispatcher 叫contextDispatcher 会自动注入,你可以用来传递事件
有两种基本的事你可以去做EventDipatcher调度事件和监听他们
dispatcher.AddListener("FIRE_MISSILE", onMissileFire);
事件会处于监听状态,知道FIRE_MISSILE事件被处罚,然后执行对应的onMissileFire方法
也可以通过枚举实现
dispatcher.AddListener(AttackEvent.FIRE_MISSILE, onMissileFire);
dispatcher.RemoveListener(AttackEvent.FIRE_MISSILE, onMissileFire);
dispatcher.UpdateListener(true, AttackEvent.FIRE_MISSILE, onMissileFire);
调用的方法可以有一个参数或者没有,这取决于你关心的事件效率
private void onMissileFire()
//this works...
private void onMissileFire(IEvent evt)
//...and so does this.
Vector3 direction = evt.data as Vector3;
dispatcher.Dispatch(AttackEvent.FIRE_MISSILE);
这种形式的调度将生成一个新的TmEvent& 调用任何监听对象,但是因为你没有提供数据,数据字段的TmEvent当然会是零。 你也可以调度和提供数据:
Vector3 orientation = gameObject.transform.localRotation.eulerA
dispatcher.Dispatch(AttackEvent.FIRE_MISSILE, orientation);
可以自己创建TmEvent调度
Vector3 orientation = gameObject.transform.localRotation.eulerATmEvent evt = new TmEvent(AttackEvent.FIRE_MISSILE, dispatcher, this.orientation);
dispatcher.Dispatch(evt);
&The command extension(命令扩展)
&除了绑定事件的方法,可以将其绑定到Commands。命令是控制器结构MVC的指挥者在strangeioc的MVCSContext中 CommandBinder监听每一个dispatcher的调度(当然你可以改变这个如果你想在自己的上下文)。信号,下面描述,也可以绑定到命令。当一个事件或信号被调度,
using mand.
using com.example.spacebattle.
namespace com.example.spacebattle.controller
class StartGameCommand : EventCommand
public ITimer gameTimer{get;set;}
override public void Execute()
gameTimer.start();
dispatcher.dispatch(GameEvent.STARTED);
但异步命令, 像网络请求&& 可以这样做&& Retain() and Release()
using mand.
using com.example.spacebattle.
namespace com.example.spacebattle.controller
class PostScoreCommand : EventCommand
IServer gameServer{get;set;}
override public void Execute()
int score = (int)evt.
gameServer.dispatcher.AddListener(ServerEvent.SUCCESS, onSuccess);
gameServer.dispatcher.AddListener(ServerEvent.FAILURE, onFailure);
gameServer.send(score);
private void onSuccess()
gameServer.dispatcher.RemoveListener(ServerEvent.SUCCESS, onSuccess);
gameServer.dispatcher.RemoveListener(ServerEvent.FAILURE, onFailure);
//...do something to report success...
Release();
private void onFailure(object payload)
gameServer.dispatcher.RemoveListener(ServerEvent.SUCCESS, onSuccess);
gameServer.dispatcher.RemoveListener(
ServerEvent.FAILURE, onFailure);
//...do something to report failure...
Release();
如果使用完不进行Release()可能会导致内存泄露&
commandBinder.Bind(ServerEvent.POST_SCORE).To&PostScoreCommand&();
您可以将多个命令绑定到单个事件如果你喜欢
commandBinder.Bind(GameEvent.HIT).To&DestroyEnemyCommand&().To&UpdateScoreCommand&();
解除命令绑定Unbind
commandBinder.Unbind(ServerEvent.POST_SCORE);
一次性的指令
commandBinder.Bind(GameEvent.HIT).To&DestroyEnemyCommand&().Once();
按顺序执行绑定&& InSequence& 会一直执行到最后的命令 或者其中一个命令失败。& 命令可以在任何时候调用Fail()&& 这会打破这个序列& 这可以用于建立一个链相关的事件& 为构建有序的动画,或制定一个守卫,以确定是否应该执行一个命令。
commandBinder.Bind(GameEvent.HIT).InSequence()
.To&CheckLevelClearedCommand&()
.To&EndLevelCommand&()
.To&GameOverCommand&();
&The signal extension(消息扩展)
信号是一个调度机制,另一种选择EventDispatcher 相比于EventDispatcher& 信号有两个优点& 1. 分发结果不再创建实例,因此也不需要GC回收更多的辣鸡& 2. 更安全 当消息与回调不匹配时会断开执行,官网也推荐使用Singal来兼容后续版本
创建两个信号,每一个都有一个参数
Signal&int& signalDispatchesInt = new Signal&int&();
Signal&string& signalDispatchesString = new Signal&string&();signalDispatchesInt.AddListener(callbackInt);      //Add a callback with an int parametersignalDispatchesString.AddListener(callbackString);    //Add a callback with a string parametersignalDispatchesInt.Dispatch(42);        //dispatch an intsignalDispathcesString.Dispatch("Ender wiggin");      //dispatch a stringvoid callbackInt(int value){    //Do something with this int}void callbackString(string value){    //Do something with this string}
消息最多可以使用四个参数
Signal&T, U, V, W& signal = new Signal&T, U, V, W&();
子类可以编写自己的信号
using UnityE
using strange.extensions.signal.
namespace mynamespace
//We're typing this Signal's payloads to MonoBehaviour and int
public class ShipDestroyedSignal : Signal&MonoBehaviour, int&
信号映射到命令
protected override void addCoreComponents()
base.addCoreComponents();
injectionBinder.Unbind&ICommandBinder&();
injectionBinder.Bind&ICommandBinder&().To&SignalCommandBinder&().ToSingleton();
这告诉strangeioc 我们做了默认CommandBinder SignalCommandBinder取而代之。 所以是信号触发命令 而不是事件 。 strangeioc& 只支持 事件或者信号中的一个映射命令,而不是两个都是。
信号绑定&& 依旧使用commandBinder
commandBinder.Bind&SomeSignal&().To&SomeCommand&();
映射一个信号到命令& 会自动创建一个injection映射& 你可以通过[Inject]标签 检索
public ShipDestroyedSignal shipDestroyedSignal{get; set;}
commandBinder.Bind&ShipDestroyedSignal&().To&ShipDestroyedCommand&();
在ShipMediator,我们注入信号,然后调度
public ShipDestroyedSignal shipDestroyedSignal{get; set;}
private int basePointV //imagining that the Mediator holds a value for this ship
//Something happened that resulted in destruction
private void OnShipDestroyed()
shipDestroyedSignal.Dispatch(view, basePointValue);
派遣一个信号通过SignalCommandBinder映射结果的实例化ShipDestroyedCommand:
using mand.
using UnityE
namespace mynamespace
//Note how we extend Command, not EventCommand
public class ShipDestroyedCommand : Command
public MonoBehaviour view{ get; set;}
public int basePointValue{ get; set;}
public override void Execute ()
//Do unspeakable things to the destroyed ship
如您所见,映射的方法非常类似于信号命令的方法使用事件
两个重要问题:第一,而信号支持多个相同类型的参数,注射。 因此不可能对一个信号与相同类型的两个参数映射到一个命令
//This works
Signal&int, int& twoIntSignal = new Signal&int, int&();
twoIntSignal.AddListener(twoIntCallback);
//This fails
Signal&int, int& twoIntSignal = new Signal&int, int&();
commandBinder.Bind(twoIntSignal).To&SomeCommand&();
override public void Launch()
base.Launch();
//Make sure you've mapped this to a StartCommand!
StartSignal startSignal= (StartSignal)injectionBinder.GetInstance&StartSignal&();
startSignal.Dispatch();
映射没有命令的信号&
一个信号映射到一个命令会自动创建一个映射,您可以检索通过注入到其他地方&& 但是如果你想注入信号没有绑定到一个命令& 使用injectionBinder只需将它映射
injectionBinder.Bind&ShipDestroyedSignal&().ToSingleton();
The mediation extension(调解器(中介模式))
MediationContext是唯一一个专为unity设计的部分,因为mediation关心的是对view(GameObject)的操作。由于view部分天生的不确定性,我们推荐view由两种不同的monobehavior组成:View and Mediator
view就是mvc中的v,一个view就是一个你可以编写的逻辑,控制可见部分的monobehavior 这个类可以附加(拖拽)到unity编辑器来管理GameObject 但是不建议将mvc中的models和controller逻辑卸载view中
Mediator类的职责是执行view和整个应用的运行。他会获取整个app中分发和接收时间和消息。但是因为mediator的设计,建议使用命令模式(command)来做这部分功能
using Strange.extensions.mediation.
using com.example.spacebattle.
using com.example.spacebattle.
namespace com.example.spacebattle.view
class DashboardMediator : EventMediator
public DashboardView view{get;set;}
override public void OnRegister()
view.init();
dispatcher.AddListener
(ServiceEvent.FULFILL_ONLINE_PLAYERS, onPlayers);
dispatcher.Dispatch
(ServiceEvent.REQUEST_ONLINE_PLAYERS);
override public void OnRemove()
dispatcher.RemoveListener
(ServiceEvent.FULFILL_ONLINE_PLAYERS, onPlayers);
private void onPlayers(IEvent evt)
IPlayers[] playerList = evt.data as IPlayers[];
view.updatePlayerCount(playerList.Length);
1.DashboardView注入可以使 Mediator 知道具体的view
2.注入完成后OnRegister()方法会立即执行,可以用这个方法来做初始化& 像上面做的那样 初始化 然后做重要的数据请求
3.contextDispatcher可以扩展任何的EventMediator
4.OnRemove()清理时使用,当一个view销毁前被调用,移除时记得删除你的监听
5.例子中的view暴露两个接口init()和updatePlayerCount(float value),但是程序在设计时 你需要更多,但是原则是相同的& 限制中介除了薄任务之间的传递信息的查看和其他应用程序
绑定一个界面到Mediator
mediationBinder.Bind&DashboardView&().To&DashboardMediator&();
值得注意的几点
1.不是所有的MonoBehaviour被限制为一个View&
2.中介者绑定是实例对实例的,也就是说一个view对应一个mediator,如果有很多view,也就会有很多的mediator
The context extension(上下文扩展)
MVCSContext包含EventDispatcher(事件分发),injectionBinder(注入绑定),MediationBinder(中介绑定),CommandBinder(命令绑定)
可以重新将CommandBinder绑定到SignalCommandBinder&& 命令和中介依托注入,context可以为命令和中介的绑定提供关联
建立一个项目,需要重新MVCSContext或者Context,一个app也可以包换多个Contexts 这样可以使你的app更高的模块化,因此,一个app可以独立的设计为聊天模块,社交模块& 最终他们会整合到一起成为一个完整的app
暂时记录到这里 剩下的 下一章补完
阅读(...) 评论()先创建TestRoot
using UnityE
using System.C
using strange.extensions.context.
public class TestRoot : ContextView {
void Start()
context = new TestContext(this);
创建TestContext&& 在TestContext中我们需要把事件命令修改为 信号命令
using UnityE
using System.C
using strange.extensions.context.
using strange.extensions.context.
using mand.
using mand.
public class TestContext : MVCSContext {
public TestContext(MonoBehaviour view)
: base(view)
public TestContext(MonoBehaviour view, ContextStartupFlags flags)
: base(view, flags)
     override&public&IContext&Start()
&&&&&&& base.Start();
&&&&&&& StartSignal&startSignal&=&(StartSignal)injectionBinder.GetInstance&StartSignal&();
&&&&&&& startSignal.Dispatch();
&&&&&&& return&this;
protected override void addCoreComponents()
base.addCoreComponents();
injectionBinder.Unbind&ICommandBinder&();
injectionBinder.Bind&ICommandBinder&().To&SignalCommandBinder&().ToSingleton();
protected override void mapBindings()
injectionBinder.Bind&SuccessSignal&().ToSingleton();&&&&&&& injectionBinder.Bind&IService&().To&TestService&();&&&&&&& mediationBinder.Bind&TestView&().To&TestMediator&();&&&&&&& commandBinder.Bind&RequestSignal&().To&RequestCommand&();&&&&&&& commandBinder.Bind&StartSignal&().To&StartCommand&().Once();
strange中IcommandBinder 事件绑定是在addCoreComponents中进行的 所以我们重写他 调用它原本的方法 再将ICommandBinder移除,在将他绑定到信号上signalCommandBinder& 重写Start()& 然后派发& 这样就完成了&&&&&&& 最后在mapBinding中进行之前一样的绑定 。
我们写一个脚本 把所有的信号都放在里面。&& 在具体情况中可以分模块将信号放在一起
  public class StartSignal : Signal
public class ClickSignal : Signal
public class RequestSignal : Signal&string&
public class SuccessSignal : Signal
StartCommand与之前的事件方法没有区别
public class StartCommand : Command
[Inject(ContextKeys.CONTEXT_VIEW)]
public GameObject contextView { get; set; }
public override void Execute()
GameObject test = new GameObject("test");
test.AddComponent&TestView&();
test.transform.SetParent(contextView.transform);
TestView 有略微的不同&&& 直接实例信号进行派发
public class TestView : View
public ClickSignal signal_Click = new ClickSignal();
void OnGUI()
if (GUI.Button(new Rect(0, 0, 100, 40), "click"))
signal_Click.Dispatch();
在TestMediator中进行监听& 然后执行方法
public class TestMediator : Mediator
public TestView view { get; set; }
public RequestSignal signal_Request { get; set; }
public override void OnRegister()
view.signal_Click.AddListener(OnClick);
public void OnClick()
signal_Request.Dispatch("");
当被点击后会进行signal_Request信号的事件派发&& RequestSignal 通过注入获取
在RequestCommand中& 我们service 通过注入获取& 然后对他进行了signal_succesd信号的监听
public class RequestCommand : Command
public IService service { get; set; }
public override void Execute()
service.signal_succesd.AddListener(OnComplete);
service.Request();
void OnComplete()
service.signal_succesd.RemoveListener(OnComplete);
Debug.Log("get data finish");
Release();
既然添加了监听 那么肯定有地方会进行成功后的信号派发&&& 在TestService 中& 我们对成功的信号进行派发
public class TestService : IService
[Inject(ContextKeys.CONTEXT_VIEW)]
public GameObject contextView { get; set; }
public SuccessSignal signal_succesd { get; set; }
public void Request()
contextView.GetComponent&MonoBehaviour&().StartCoroutine(Wait());
/// &summary&
/// 模拟网络请求延迟1秒
/// &/summary&
/// &returns&&/returns&
IEnumerator Wait()
yield return new WaitForSeconds(1);
signal_succesd.Dispatch();
这样& 我们就实现了信号的机制& 信号也是官方推荐的方法
阅读(...) 评论()

我要回帖

更多关于 unity3d command line 的文章

 

随机推荐