InvokeOnAppThread在应用程序线程上调用会引发错误

时间:2017-10-13 02:36:29

标签: c# multithreading unity3d

在Unity中,我在附加到通用游戏对象的脚本中有以下代码,其中包含多维数据集:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;
//using System.Runtime.Tasks;

public class ExampleScript : MonoBehaviour {

    // Use this for initialization
    void Start () 
    {
        Debug.Log ("Start():: Starting");
        //SlowJob ();

        Thread myThread = new Thread (SlowJob);

        myThread.Start ();

        Debug.Log ("Start():: Done");

    }

    // Update is called once per frame
    void Update () {

        //Option 1) This will move the cube in the application thread
        //this.transform.Translate (Vector3.up * Time.deltaTime);

    }


    void SlowJob()
    {

        Debug.Log ("ExampleScript::SlowJob() --Doing 1000 things, each taking 2ms ");

        System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
        sw.Start ();

        for (int i = 0; i < 1000; i++) 
        {
            //Option 2) We are trying to move the cube in the secondary thread! ooops!!
            //this.transform.Translate (Vector3.up * 0.002f);
            //get_transform can only be called from the main thread

            //Option 3) We are going to try to use a delegate on application thread 
            UnityEngine.WSA.Application.InvokeOnAppThread (()=>{
                this.transform.Translate (Vector3.up * 0.002f);
            },false);

            //Option4
/*          UnityEngine.WSA.Application.InvokeOnUIThread (()=>{
                this.transform.Translate (Vector3.up * 0.002f);
            },false);
*/
            Thread.Sleep (2);  //sleep for 2ms

        }

        sw.Stop ();

        Debug.Log ("ExampleScript::SlowJob() --Done!  Elapsed Time:" + sw.ElapsedMilliseconds / 1000f);


    }
}

正如您所看到的,有一个SlowJob函数正在另一个线程上执行。 现在,我想更新一致的东西(在这种情况下是立方体) 所以我尝试了四件事:

  1. 在主线程中移动多维数据集。这很好,因为它应该
  2. 从辅助线程移动多维数据集。这当然不起作用。错误说&#34; get_transform只能从主线程调用。这当然是预期的。
  3. 使用InvokeOnAppThread移动多维数据集。 (稀缺)文档说这会在应用程序线程上调用委托。我在想这应该工作。但它会引发同样的错误
  4. 只是为了尝试我也尝试了InvokeOnUIThread同样的错误。
  5. 我的问题是为什么选项3不起作用?我认为InvokeOnAppThread用于这些情况

    (以防万一,只有一个关于InvokeOnAppThread的问题。问我。这是一个不同的问题所以这个不是重复的问题)

    我的问题不在于如何从另一个线程调用统一内容(尽管它也解决了这个问题)。我的问题是为什么InvokeOnAppThread不起作用?

    我知道有解决这个问题的方法很复杂。这不是这个问题的关键

    我再说一遍这不是一个重复的问题。

    非常感谢任何有用的建议

1 个答案:

答案 0 :(得分:2)

  

我的问题是为什么选项3不起作用?我以为InvokeOnAppThread   用于这些案件

import React, { Component } from 'react'; import './Hall.css'; class HallCol extends Component { constructor(props) { super(props); this.state = { chair_cls:'chair-default' }; this.handleClick = this.handleClick.bind(this); } handleClick(e) { let chair_cls = null; if(this.state.chair_cls==="chair-default") { chair_cls = 'chair-sold'; this.props.updateCount(1, this.props.seat_number); } else { chair_cls = 'chair-default'; this.props.updateCount(-1, this.props.seat_number); } this.setState({ chair_cls: chair_cls }); } render(){ return( <div className={this.state.chair_cls} onClick={this.handleClick}> <div className="backrest"> <p>{this.props.seat_number}</p> </div> <div className="armrest-left"> </div> <div className="armrest-right"> </div> </div> ); } } class Table extends React.Component { constructor() { super(); this.genRow = this.genRow.bind(this); // this is method binding } genRow() { var rows = this.props.rows; return rows.map(function(v, i) { var tmp = v.map(function(v2, j) { return ( <td key={'td' + i + '_' + j} className='chair-cell' > {v2} </td> ); }); return ( <tr key={'tr' + i}> {tmp} </tr> ) }); } render() { return ( <table className="hall-grid" > <tbody> {this.genRow()} </tbody> </table> ); } } class Hall extends React.Component { constructor(props) { super(props); var rows_num = this.props.rows; var cols_num = this.props.cols; this.AddRow = this.AddRow.bind(this); this.updateSeats = this.updateSeats.bind(this); var row = []; for (var i = 0; i < rows_num; i++) { var col = []; for (var k = 0; k< cols_num; k++) { col.push(<HallCol row = {i+1} seat_number = {k+1} updateCount={this.updateSeats} />); // bind the passed function to parent } row.push(col); } this.state = { rows: row, bookedSeats: [], count: 0 }; } AddRow() { let newRows = this.state.rows; newRows.push([0, 0]); this.setState({rows: newRows}); } updateSeats(val, seat_number) { let bookedSeatsUpdated; if( val === 1 ) { bookedSeatsUpdated = this.state.bookedSeats.concat(seat_number); } else { bookedSeatsUpdated = this.state.bookedSeats; let index = bookedSeatsUpdated.indexOf(seat_number); bookedSeatsUpdated.splice(index,1); } this.setState({ bookedSeats: bookedSeatsUpdated, count: this.state.count + val }); } render() { return ( <div className="hall"> <Table rows={this.state.rows} /> <button className = "btn-default" onClick={() => { alert(this.state.count + 'seats : ' + this.state.bookedSeats); } }> TOTAL SOLD </button> </div> ); } } export default Hall; 函数不用于从另一个Thread调用Unity的主线程。它用于在Unity和Windows App Thread之间进行通信。使用XAML以Windows本地方式制作Windows应用程序时使用此功能,然后决定将Unity集成到此项目中。您可以将它用作桥接器,从App主线程上的本机端向Unity发送消息,反之亦然。它并不意味着从你创建的另一个InvokeOnAppThread中调用,就像你想象的那样,你正在使用它。

ThreadInvokeOnAppThread函数的记录很少,但为了简化它们:

InvokeOnUIThread - 用于调用从XAML到Unity的方法。

InvokeOnAppThread - 用于调用Unity到XAML的方法。

这是过去的习惯,希望它仍然有办法。有关示例,请参阅Ref1Ref2

此外,它来自InvokeOnUIThread命名空间,一旦您使用它,您就无法为除Windows平台之外的任何其他平台构建您的应用。您的项目不会为Android,iOS,Mac和其他人构建。

最后,您没有与之通信的Windows XAML应用,因此您不需要WSA。同样,InvokeOnAppThread不用于在Thread和Unity的主线程之间进行通信。它用于在使用XAML和Unity制作的程序的Windows端之间进行通信。您只想在另一个InvokeOnAppThread中使用Unity API。你要么必须自己创建函数/包装器,要么使用我已经从here创建的函数/包装器。