u3d插件xLua[八]例7 AsyncTest

讲解xLua例7 AsyncTest,用顺序写法代替传回调写法

一.例7 AsyncTest代码分析

先说结论,这个demo目的是用顺序写法代替传回调写法,实现上是用Lua的协程API,控制函数执行,中断

1.1 AsyncTest.cs

执行async_test.lua的入口文件

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

namespace XLuaTest
{
    public class AsyncTest : MonoBehaviour
    {
        LuaEnv luaenv = null;

        void Start()
        {
            luaenv = new LuaEnv();
            luaenv.DoString("require 'async_test'");
        }

        // Update is called once per frame
        void Update()
        {
            if (luaenv != null)
            {
                luaenv.Tick();
            }
        }
    }
}

1.2 async_test.lua

业务代码,在buy函数中实现了将给message_box传回调的做法写成了顺序执行的写法,这种写法必须吃透掌握,在xLua项目实战中可能大量使用,需要扫清读写障碍。

local util = require 'xlua.util'
local message_box = require 'message_box'

-------------------------async_recharge-----------------------------
local function async_recharge(num, cb) --模拟的异步充值
    print('requst server...')
    cb(true, num)
end

local recharge = util.async_to_sync(async_recharge)
-------------------------async_recharge end----------------------------
local buy = function()
    message_box.alert("您余额不足,请充值!", "余额提醒")
	if message_box.confirm("确认充值10元吗?", "确认框") then
		local r1, r2 = recharge(10)
		print('recharge result:', r1, r2)
		message_box.alert("充值成功!", "提示")
	else
	    print('cancel')
	    message_box.alert("取消充值!", "提示")
	end
	print('recharge finished')
end
--将按钮监听点击事件,绑定buy方法
CS.UnityEngine.GameObject.Find("Button"):GetComponent("Button").onClick:AddListener(util.coroutine_call(buy))

1.3 message_box.lua

本质上就是调用util的async_to_sync方法

local util = require 'xlua.util'

local sync_alert = util.async_to_sync(CS.XLuaTest.MessageBox.ShowAlertBox)
local sync_confirm = util.async_to_sync(CS.XLuaTest.MessageBox.ShowConfirmBox) 

--构造alert和confirm函数
return {
    alert = function(message, title)
		 sync_alert(message, title)
    end;
	
	confirm = function(message, title)
		local ret = sync_confirm(message, title)
		return ret == true
    end;
 }

1.4 util.lua

函数coroutine_call:创建一个协程并运行(coroutine.create创建的协程初始状态为suspend)

函数async_to_sync:这个函数是理解串行写法替代传回调的关键:

1.每一次在业务区调用async_to_sync时,async_func执行一次(C#的ShowAlertBox,用来显示对话框),执行coroutine.yield(),业务区代码会中断:状态从running变成suspend

2.调用async_func时,cb_func会被传到C#侧的onFinished委托,点击button后cb_func会执行

3.cb_func执行后,业务区代码会继续执行直到下一次执行async_to_sync

local unpack = unpack or table.unpack

local function async_to_sync(async_func, callback_pos)
    return function(...)
        local _co = coroutine.running() or error ('this function must be run in coroutine')
        local rets
        local waiting = false
        local function cb_func(...)
            if waiting then
                assert(coroutine.resume(_co, ...))
            else
                rets = {...}
            end
        end
        local params = {...}
        table.insert(params, callback_pos or (#params + 1), cb_func)
        async_func(unpack(params))
        if rets == nil then
            waiting = true
            rets = {coroutine.yield()}
        end
        
        return unpack(rets)
    end
end

local function coroutine_call(func)
    return function(...)
        local co = coroutine.create(func)
        assert(coroutine.resume(co, ...))
    end
end

1.5 MessageBox.cs

主要是UI上的实现

using UnityEngine;
using UnityEngine.UI;
using XLua;
using System.Collections.Generic;
using System;
using UnityEngine.Events;

namespace XLuaTest
{
    public class MessageBox : MonoBehaviour
    {

        public static void ShowAlertBox(string message, string title, Action onFinished = null)
        {
            var alertPanel = GameObject.Find("Canvas").transform.Find("AlertBox");
            if (alertPanel == null)
            {
                alertPanel = (Instantiate(Resources.Load("AlertBox")) as GameObject).transform;
                alertPanel.gameObject.name = "AlertBox";
                alertPanel.SetParent(GameObject.Find("Canvas").transform);
                alertPanel.localPosition = new Vector3(-6f, -6f, 0f);
            }

            alertPanel.Find("title").GetComponent<Text>().text = title;
            alertPanel.Find("message").GetComponent<Text>().text = message;

            var button = alertPanel.Find("alertBtn").GetComponent<Button>();
            UnityAction onclick = () =>
            {
                if (onFinished != null)
                {
                    onFinished();
                }
                button.onClick.RemoveAllListeners();
                alertPanel.gameObject.SetActive(false);
            };
            //防止消息框未关闭时多次被调用
            button.onClick.RemoveAllListeners();
            button.onClick.AddListener(onclick);
            alertPanel.gameObject.SetActive(true);
        }

        public static void ShowConfirmBox(string message, string title, Action<bool> onFinished = null)
        {
            var confirmPanel = GameObject.Find("Canvas").transform.Find("ConfirmBox");
            if (confirmPanel == null)
            {
                confirmPanel = (Instantiate(Resources.Load("ConfirmBox")) as GameObject).transform;
                confirmPanel.gameObject.name = "ConfirmBox";
                confirmPanel.SetParent(GameObject.Find("Canvas").transform);
                confirmPanel.localPosition = new Vector3(-8f, -18f, 0f);
            }

            confirmPanel.Find("confirmTitle").GetComponent<Text>().text = title;
            confirmPanel.Find("conmessage").GetComponent<Text>().text = message;

            var confirmBtn = confirmPanel.Find("confirmBtn").GetComponent<Button>();
            var cancelBtn = confirmPanel.Find("cancelBtn").GetComponent<Button>();
            Action cleanup = () =>
            {
                confirmBtn.onClick.RemoveAllListeners();
                cancelBtn.onClick.RemoveAllListeners();
                confirmPanel.gameObject.SetActive(false);
            };

            UnityAction onconfirm = () =>
            {
                if (onFinished != null)
                {
                    onFinished(true);
                }
                cleanup();
            };

            UnityAction oncancel = () =>
            {
                if (onFinished != null)
                {
                    onFinished(false);
                }
                cleanup();
            };

            //防止消息框未关闭时多次被调用
            confirmBtn.onClick.RemoveAllListeners();
            confirmBtn.onClick.AddListener(onconfirm);
            cancelBtn.onClick.RemoveAllListeners();
            cancelBtn.onClick.AddListener(oncancel);
            confirmPanel.gameObject.SetActive(true);
        }
    }

    public static class MessageBoxConfig
    {
        [CSharpCallLua]
        public static List<Type> CSharpCallLua = new List<Type>()
    {
        typeof(Action),
        typeof(Action<bool>),
        typeof(UnityAction),
    };
    }
}

二.例7 AsyncTest运行展示

运行效果:

三.例7 AsyncTest总结

1.顺序写法代替传回调写法这种做法要能理解,会使用

2.util中的async_recharge和coroutine_call在商业xLua项目中可能大量使用,可以在项目中搜索出现数量

内容概要:本文针对有源中点箝位(ANPC)三电平并网逆变器在复杂电网环境下的性能瓶颈,提出了一种融合双极性倍频脉宽调制(DPWMA)、正负序分离锁相技术与电网电压前馈控制的一体化高性能并网控制策略。通过深入分析ANPC三电平拓扑在开关损耗均衡性、中点电位稳定性及输出电能质量方面的固有优势,构建了高可靠性的硬件基础;在此之上,DPWMA调制策略有效提升了开关频率利用率,显著降低了输出电流谐波含量;正负序分离锁相环(SRF-PLL)精准提取电网正序分量,解决了电网不平衡工况下传统锁相技术存在的相位检测偏差与并网电流不对称问题;电网电压前馈控制则通过前馈补偿机制,提前抑制电网电压扰动对并网电流的直接影响,大幅增强了系统在电压骤升、骤降等动态工况下的响应速度与鲁棒性。研究通过Simulink搭建了完整的仿真模型,对稳态运行、电网不平衡及动态切换等多种工况进行了全面验证,结果表明该复合控制策略能显著提升并网电能质量、锁相精度与系统动态稳定性,适用于新能源发电、大功率工业变流等对并网性能要求严苛的应用场景。; 适合人群:具备电力电子与电力系统基础知识,从事新能源发电、微电网、大功率变流器、电能质量治理等相关领域研究的研发人员及高校研究生。; 使用场景及目标:①解决传统三电平逆变器在电网不平衡条件下锁相不准、电流畸变严重的问题;②提升并网逆变器在电压骤升/骤降等动态扰动工况下的响应速度、抗扰能力与并网稳定性;③为高性能、高可靠性的并网控制系统设计提供一套可复现、可验证的技术方案与完整的仿真模型参考。; 阅读建议:建议读者结合文中提供的Simulink仿真模型,按照“拓扑分析-控制策略设计-仿真验证”的逻辑主线,循序渐进地理解各模块的设计原理,重点钻研正负序分离锁相与电网电压前馈控制的实现细节,并通过设置不同的电网扰动工况进行仿真实验,对比分析控制效果,从而深入掌握多技术协同优化的内在机理与工程应用价值。
代码转载自:https://pan.quark.cn/s/679a7257f458 在Windows操作系统环境中,开发多线程程序是一项普遍存在的编程需求,其主要目的是为了达成不同任务的并行处理,从而优化程序的执行效能。在C++开发情境下,我们一般会借助WinAPI提供的`_beginthreadex`函数来进行线程的构建,此方法具备跨操作系统的兼容性,并且是C运行时库(CRT)所包含的一部分。本文将深入剖析如何运用`_beginthreadex`函数来构建多线程以及相关的技术要点。 首先,让我们明确`_beginthreadex`函数的基本操作方法。该函数需要接收若干个参数,包括一个指向安全属性的指针、初始堆栈的尺寸、一个线程执行函数的指针、传递给线程执行函数的参数、线程的创建标识以及一个存放线程标识符的指针。线程执行函数是新线程将要运行的代码的起始位置。下面给出一个基础的实代码: ```cpp uintptr_t thread_id; HANDLE hThread = (HANDLE)_beginthreadex( NULL, // 指向安全属性的指针,通常设置为NULL 0, // 堆栈尺寸,若传入0则表示采用系统默认值 ThreadFunction, // 指向线程执行函数的指针 NULL, // 传递给线程执行函数的参数,可以根据需求自定义 CREATE_SUSPENDED, // 线程的创建标识,可以选择使用CREATE_SUSPENDED来使线程处于挂起状态 &thread_id // 用于接收线程标识符的指针 ); ``` 在此代码中,`ThreadFunction`代表用户自定义的函数,它将作为新线程执行的起始点。如: ```cpp D...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ellis1970

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值