【Unity】线程安全的消息传输机制,仿照Cocos实现

近期用到了网络通信的方法,虽然unity可以用协程来实现异步操作,不过坑爹的队友不会用,他用的是传统的开线程的方法,这样就会出现线程安全的问题,然后现有的消息通信机制无法满足需求了,就得改了。还好我机智的看过Cocos2dx中消息机制的实现原理,顺手改了一下,下面贴源码:(源码后有解释)

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/**
 * 消息派发类
 */
namespace Assets.TGUI.UIScript
{
    public class CDispatcher
    {
        //单例
        public static readonly CDispatcher Instance = new CDispatcher();

        //消息委托函数
        public delegate void noticeDelegate(object[] data);

        /// <summary>
        /// 消息Key
        /// </summary>
        public struct Key
        {
            public string name;
            public object target;

            public Key(string _name, object _target)
            {
                name = _name;
                target = _target;
            }
        }

        //存储消息列表
        private Dictionary<Key, noticeDelegate> m_noticeDict;

        private List<KeyValuePair<Key, object[]>> m_noticeRequest;

        private List<KeyValuePair<Key, object[]>> m_tempRequest;

        private CDispatcher()
        {
            m_noticeDict = new Dictionary<Key, noticeDelegate>();
            m_noticeRequest = new List<KeyValuePair<Key, object[]>>();
            m_tempRequest = new List<KeyValuePair<Key, object[]>>();
        }

        /// <summary>
        /// 循环遍历 执行消息请求
        /// </summary>
        public IEnumerator Dispatcher()
        {
            Debug.Log("MSG: Start Dispatcher");
            do
            {
                if (m_tempRequest.Count != 0)
                {
                    lock (m_tempRequest)
                    {
                        foreach (var item in m_tempRequest)
                        {
                            m_noticeRequest.Add(new KeyValuePair<Key, object[]>(item.Key, item.Value));
                        }
                        m_tempRequest.Clear();
                    }

                    foreach (var item in m_noticeRequest)
                    {
                        if (m_noticeDict.ContainsKey(item.Key))
                        {
                            m_noticeDict[item.Key](item.Value);
                        }
                    }

                    m_noticeRequest.Clear();
                }
                yield return new WaitForFixedUpdate();
            } while (true);
        }

        /**
         * 发送消息
         * @param notifyName 消息类型
         * @param data 携带参数
         */
        public void sendNotification(string noticeName, object[] data = null)
        {
            sendNotification(noticeName, null, data);
        }

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="noticeName"></param>
        /// <param name="target"></param>
        /// <param name="data"></param>
        public void sendNotification(string noticeName, object target, object[] data)
        {
            m_tempRequest.Add(new KeyValuePair<Key, object[]>(new Key(noticeName, target), data));
        }

        /// <summary>
        /// 发送消息 附带的数据是发送者本身的对象
        /// </summary>
        /// <param name="noticeName"></param>
        /// <param name="target"></param>
        /// <param name="source"></param>
        public void sendNotification(string noticeName, object target, object source)
        {
            sendNotification(noticeName, target, new object[] { source });
        }

        /// <summary>
        /// 获取到源类型变量
        /// (与sendNotification(string noticeName,
        /// object target, object source)对应)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="data"></param>
        /// <returns></returns>

        public T GetSourceObject<T>(object[] data)
        {
            return (T)data[0];
        }

        public void addObserver(string noticeName, noticeDelegate notice)
        {
            addObserver(noticeName, null, notice);
        }

        public void addObserver(string noticeName, object target, noticeDelegate notice)
        {
            Key key = new Key(noticeName, target);
            if (!m_noticeDict.ContainsKey(key))
            {
                m_noticeDict.Add(key, notice);
            }
        }

        public void RemoveObserver(string noticeName)
        {
            RemoveObserver(noticeName, null);
        }

        public void RemoveObserver(string noticeName, object target)
        {
            Key key = new Key(noticeName, target);

            if (!m_noticeDict.ContainsKey(key))
            {
                m_noticeDict.Remove(key);
            }
        }
    }
}

方法稍微有点略多,但是值得关注的方法就是下面几个

IEnumerator Dispatcher()
public void sendNotification(...)
public void addObserver(...)
public void RemoveObserver(...)

首先来说第一个,第一个是消息循环遍历的方法,需要在游戏主对象中的start方法中使用协程开启消息循环遍历,写法如下:

        //开启消息循环
        StartCoroutine(CDispatcher.Instance.Dispatcher());

然后和Cocos2dx一样,添加观察者

CDispatcher.Instance.addObserver("消息名字", [目标对象], 方法);

然后发送消息

CDispatcher.Instance.sendNotification("消息名字",[目标对象],[附加数据]);

下面是一个完整的使用例子:

protected void Start()
    {
        //开启消息循环
        StartCoroutine(CDispatcher.Instance.Dispatcher());
        CDispatcher.Instance.addObserver("我要睡觉", x => Debug.Log("睡觉"));
        CDispatcher.Instance.sendNotification("我要睡觉");
}

最后当然输出“睡觉”咯

时间: 2024-10-16 01:53:21

【Unity】线程安全的消息传输机制,仿照Cocos实现的相关文章

JMS消息传输机制

JMS消息传送模型: 消息传送机制, 是基于拉取(pull)或者轮询(polling)的方式.  JMS具备两种"消息传送模型": P2P和Pub/sub. (1) P2P:点对点消息传送模型, 允许JMS客户端通过队列(queue)这个虚拟通道来同步或异步发送消息; 消息的生产者为Sender, 消费者为receiver.   receiver主动到队列中请求消息,而不是JMS提供者将消息推送到客户端;   主要原因是一个队列通道可能有多个receiver,每个receiver可能对

医疗行业多层级复杂网络环境下的消息传输(远程会诊)架构与实现

近期接手一个针对医疗系统远程会诊平台的技术改造工作,这项工作中的一些技术问题颇具代表性,我会在此记录这一工作的过程和技术细节,如果条件允许,会在 GitHub 上开源部分业务无关的纯技术实现,敬请关注.(https://github.com/iccb1013). 远程会诊平台的应用场景指的是乡镇或县卫生所,在接诊过程中,对疑难问题上报上级医疗机构,由上级医疗机构进行网络诊断并回复诊疗意见,但是这一过程,并不是简单的点对点的关系.主要特点:1)  包含多级机构:乡镇.县.区.市.省.由任意一级向上

ActiveMQ源码解析(四):聊聊消息的可靠传输机制和事务控制

在消息传递的过程中,某些情况下比如网络闪断.丢包等会导致消息永久性丢失,这时消费者是接收不到消息的,这样就会造成数据不一致的问题.那么我们怎么才能保证消息一定能发送给消费者呢?怎么才能避免数据不一致呢?又比如我们发送多条消息,有时候我们期望都发送成功但实际上其中一部分发送成功,另一部分发送失败了,没达到我们的预期效果,那么我们怎么解决这个问题呢? 前一种问题我们通过消息确认机制来解决,它分为几种模式,需要在创建session时指定是否开启事务和确认模式,像下面这样: <span style=&quo

Unity内置的三套消息发送机制的应用实例

转自http://blog.sina.com.cn/s/blog_1491e52310102wuf6.html 代码简介 : [1] 实例中包含2个类文件, SendMessage.cs 和 ReceiveMessage.cs , 分别为消息发送端和消息接收端. [2] Unity内置的消息发送系统有一个很特别的地方 - 即使接收端的方法类型为 private 或者 protected, 也能够收到信息. [3] Unity内置了3套消息机制,它们分别为 1. SendMessage() 向自己

Unity 消息发送机制 解析

该博客,只为解析,解析,解析,已经整理好,已经整理好,已经整理好.代码核心原理套用网上最流行的那一套,也是最常用游戏开发适用的消息机制.这里面加上自己的一些优化,极大的修正(哈哈),实测,没问题.万一要是出现问题,欢迎童鞋可以留言给我修正. 有童鞋可能会好奇,unity里面不是有自己的一套消息发送, 例如什么SendMessage,这...这个几乎是不能用的. 为啥不能用,看看以下是网上给的解释,自己玩玩demo还是可以用,但是实际开发,是几乎不能用的. I:它实现的是一种伪监听者模式,利用的是

ZeroMQ接口函数之 :zmq - 0MQ 轻量级消息传输内核

zmq(7) 0MQ Manual - 0MQ/3.2.5 Name zmq – ØMQ 轻量级消息传输内核 Synopsis #include <znq.h> cc [flags] files –lzmq [libraries] Description ØMQ轻量级消息传输内核是一个从标准socket接口的扩展而来的链接库,这些接口通常是由一些专门的传送中间设备来提供.ØMQ提供了一个步消息传送.多模式消息传送.消息过滤(订阅).对多种传输协议无缝接入的集合. 本文档呈现了ØMQ的概念,描述

如何优化传输机制来实现实时音视频的超低延迟?

1.前言 要在语音视频 SDK 中实现超低延迟,实时的语音视频传输机制是必不可少的,而 FEC 和 ARQ 的智能结合是实时语音视频传输机制的基石. 在语音社交.视频社交.游戏语音和互动直播等领域,关于在语音视频实时传输中实现低延迟这个议题,已经有不少的文章提出各种方案.绝大部分方案的思路都是"优化",比如说,优化编码.推流.传输和播放等各个环节. 愚以为,要在实时语音视频传输中获得超低延迟,是不能单靠挖空心思去"优化"的,而是要依靠实时的传输机制.就像高铁和火车有

MFC消息响应机制 q

MFC消息响应机制分析 1 引言微软公司提供的MFC基本类库(Microsoft Foundation Classes),是进行可视化编程时使用最为流行的一个类 库.MFC封装了大部分Windows API函数和Windows控件,使得程序的开发变得简单,极大的缩短了程序的开发 周期.MFC独创的Document/View框架结构,能够将管理数据的代码和显示数据的程序代码分开,并且设计了 一套方便的消息映射和命令传递机制,方便程序员的开发使用.其中消息映射机制本身比较庞大和复杂,对 它的分析和了

红茶一杯话Binder(传输机制篇_上)

红茶一杯话Binder (传输机制篇_上) 侯 亮 1 Binder是如何做到精确打击的? 我们先问一个问题,binder机制到底是如何从代理对象找到其对应的binder实体呢?难道它有某种制导装置吗?要回答这个问题,我们只能静下心来研究binder驱动的代码.在本系列文档的初始篇中,我们曾经介绍过ProcessState,这个结构是属于应用层次的东西,仅靠它当然无法完成精确打击.其实,在binder驱动层,还有个与之相对的结构,叫做binder_proc.为了说明问题,我修改了初始篇中的示意图