L'utilisation de l'Unité de l'API à partir d'un autre Thread ou appeler une fonction dans le Thread principal
Mon problème est que j'essaie d'utiliser l'Unité prise pour mettre en œuvre quelque chose. Chaque fois, quand je reçois un nouveau message j'ai besoin de mettre à jour vers la updattext(c'est une Unité de Texte). Cependant, Quand je fais le code suivant, le vide mise à jour n'a pas d'appeler à chaque fois.
La raison pour laquelle je ne comprend pas updatetext.GetComponent<Text>().text = "From server: "+tempMesg;
dans le vide getInformation est cette fonction est dans le fil, quand je l'inclure dans getInformation (), il viendra avec une erreur:
getcomponentfastpath can only be called from the main thread
Je pense que le problème c'est que je ne sais pas comment faire pour exécuter le thread principal et l'enfant thread en C# à l'ensemble? Il ya peut-être d'autres problèmes... j'Espère que quelqu'un peut aider..
Il y a mon code:
using UnityEngine;
using System.Collections;
using System;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine.UI;
public class Client : MonoBehaviour {
System.Net.Sockets.TcpClient clientSocket = new System.Net.Sockets.TcpClient();
private Thread oThread;
// for UI update
public GameObject updatetext;
String tempMesg = "Waiting...";
//Use this for initialization
void Start () {
updatetext.GetComponent<Text>().text = "Waiting...";
clientSocket.Connect("10.132.198.29", 8888);
oThread = new Thread (new ThreadStart (getInformation));
oThread.Start ();
Debug.Log ("Running the client");
}
//Update is called once per frame
void Update () {
updatetext.GetComponent<Text>().text = "From server: "+tempMesg;
Debug.Log (tempMesg);
}
void getInformation(){
while (true) {
try {
NetworkStream networkStream = clientSocket.GetStream ();
byte[] bytesFrom = new byte[10025];
networkStream.Read (bytesFrom, 0, (int)bytesFrom.Length);
string dataFromClient = System.Text.Encoding.ASCII.GetString (bytesFrom);
dataFromClient = dataFromClient.Substring (0, dataFromClient.IndexOf ("$"));
Debug.Log (" >> Data from Server - " + dataFromClient);
tempMesg = dataFromClient;
string serverResponse = "Last Message from Server" + dataFromClient;
Byte[] sendBytes = Encoding.ASCII.GetBytes (serverResponse);
networkStream.Write (sendBytes, 0, sendBytes.Length);
networkStream.Flush ();
Debug.Log (" >> " + serverResponse);
} catch (Exception ex) {
Debug.Log ("Exception error:" + ex.ToString ());
oThread.Abort ();
oThread.Join ();
}
// Thread.Sleep (500);
}
}
}
OriginalL'auteur user6142261 | 2016-12-26
Vous devez vous connecter pour publier un commentaire.
L'unité n'est pas
Thread
sûr, ils ont décidé de rendre impossible l'appel de leur API à partir d'un autreThread
par l'ajout d'un mécanisme de lève une exception lors de son API est utilisé à partir d'un autreThread
.Cette question a été posée à de nombreuses reprises, mais il n'y a eu aucune bonne solution/réponse à l'un d'eux. Les réponses sont généralement "utiliser un plugin" ou de faire quelque chose de pas thread-safe. J'espère que ce sera le dernier.
La solution que vous aurez l'habitude de voir sur Stackoverflow ou de l'Unité du site web du forum est d'utiliser simplement un
boolean
variable de laisser le thread principal savez que vous avez besoin pour exécuter du code dans le mainThread
. Ce n'est pas juste que ce n'est pas thread-safe et ne pas vous donner le contrôle à fournir à la fonction à appeler. Que faire si vous avez plusieursThreads
qui doivent en aviser le thread principal?Une autre solution vous allez voir, c'est d'utiliser une coroutine au lieu d'un
Thread
. Ce n' pas travail. À l'aide de coroutine pour les sockets ne changera rien. Vous aurez toujours votre la congélation problèmes. Vous devez vous en tenir à votreThread
code ou de l'utilisationAsync
.L'un des moyens de le faire est de créer une collection comme
List
. Lorsque vous besoin de quelque chose pour être exécuté dans le Thread principal, appeler une fonction qui stocke le code à exécuter dans unAction
. CopieList
deAction
à un localList
deAction
puis exécuter le code de la localeAction
dans ceList
alors queList
. Cela empêche les autresThreads
d'avoir à attendre la fin de l'exécution.Vous devez également ajouter un
volatile boolean
à informer leUpdate
fonction de qui il est le code de l'attente dans laList
à être exécuté. Lors de la copie de laList
à un localList
, qui doit être enroulé autour de lalock
mot-clé pour empêcher un autre Thread, de l'écriture à elle.Un script qui effectue ce que j'ai mentionné ci-dessus:
UnityThread
Script:UTILISATION:
Cette application vous permet d'appeler des fonctions dans le 3 les plus utilisés Unité de fonctions:
Update
,LateUpdate
etFixedUpdate
fonctions. Cela permet également de vous appeler exécuter une coroutine fonction dans le mainThread
. Il peut être étendu pour être en mesure d'appeler des fonctions dans d'autres Unité de rappel des fonctions telles queOnPreRender
etOnPostRender
.1.Tout d'abord, l'initialiser à partir de la
Awake()
fonction.2.Pour exécuter un code dans le main
Thread
partir d'un autre Thread:Cela va tourner à l'Objet courant le scipt est fixé à 90 degrés. Vous pouvez maintenant utiliser l'Unité de l'API(
transform.Rotate
) dans un autreThread
.3.Pour appeler une fonction dans le main
Thread
partir d'un autre Thread:La #2 et #3 échantillons s'exécute dans le
Update
fonction.4.Pour exécuter un code dans le
LateUpdate
fonction à partir d'un autre Thread:Exemple de ceci est une caméra de code de suivi.
5.Pour exécuter un code dans le
FixedUpdate
fonction à partir d'un autre Thread:Exemple quand on fait de la physique des choses telles que l'ajout de la force pour
Rigidbody
.6.Pour Démarrer une coroutine fonction dans le main
Thread
partir d'un autre Thread:Enfin, si vous n'avez pas besoin d'exécuter quoi que ce soit dans le
LateUpdate
etFixedUpdate
fonctions, vous devrez commenter les deux lignes de ce code ci-dessous:Cela permettra d'augmenter les performances.
Vous devez créer un script qui s'appelle "UnityThread", alors vous devez copier le
UnityThread
code dans ma réponse. S'il vous plaît dites-moi ce qui est dur?executeCoroutine
doit être à l'intérieur de la#if (ENABLE_UPDATE_FUNCTION_CALLBACK)
, sinon vous allez obtenir une erreur de compilation sur laexecuteInUpdate(() => instance.StartCoroutine(action));
ligne lorsque le symbole n'est pas défini."si
ENABLE_UPDATE_FUNCTION_CALLBACK
n'est pas définie, la fonction n'est pas inclus." C'est le problème, ce que vous avez dit n'est pas le cas. La fonctionpublic static void executeCoroutine(IEnumerator action)
est avant le#if
bloc donc siENABLE_UPDATE_FUNCTION_CALLBACK
n'est pas défini la fonctionexecuteCoroutine
existe toujours. J'ai essayé de dire vous avez besoin de déplacer le#if
12 lignes plus haut donc c'est juste avant laCOROUTINE IMPL
commentaire afin queexecuteCoroutine
etexecuteInUpdate
non-existent plus lorsque le symbole n'est pas défini.Génial solution, mec. M'a sauvé des dizaines d'heures!
OriginalL'auteur Programmer
Grande partie de l'écriture à propos des threads dans l'Unité est complètement, totalement erronée.
L'écrasante fait est que l'Unité est bien sûr totalement basé sur le cadre.
Lorsque vous travaillez dans un cadre basé sur le système, problèmes de threading sont incroyablement différent (et généralement beaucoup plus simple) que dans un système classique.
Problèmes de Threading sur un frame-based système est totalement, complètement différente que sur un système conventionnel. (À certains égards, beaucoup plus simple à utiliser parce que certaines questions n'existent tout simplement pas dans une trame de base du système.)
Disons que vous avez une Unité thermomètre d'affichage qui montre une certaine valeur
Alors il aura une fonction qui est appelée dans la mise à Jour, comme
Qui ne s'exécute une fois par image, et c'est tout.
Il est très facile d'oublier que de base en fait.
Sûr, il ne fonctionne que sur le "fil conducteur".
(Il n'y a rien d'autre dans l'Unité! Il y a juste ............... "l'Unité du fil"!)
Mais le paradigme clé à garder à l'esprit est: elle s'exécute une fois un cadre.
Maintenant, ailleurs, dans l'Thermo.cs, vous avez une fonction qui gère le concept de "nouvelle valeur est arrivé":
Note que, bien sûr, c'est une fonction de classe!
Vous ne pouvez en aucune façon de "parvenir à" une normale de l'Unité de la fonction comme ShowThermoValue!!!!!! Note de bas de page 1
Il est totalement, complètement, sans concept. Vous ne pouvez pas "chercher à" ShowThermoValue.
Tout threading "liés" à des exemples de code que vous voyez, pour l'Unité, qui tentent de "chercher à", "un fil" sont totalement et complètement erronée.
Il n'y a pas de threads à atteindre pour!
De nouveau - et c'est étonnant - si vous venez de google tout ce qui est écrit sur le web à propos des threads dans l'Unité:
De nombreux articles et publications, sont littéralement totalement, absolument, incorrect.
Disons: les valeurs arrivent très fréquemment et de façon irrégulière.
Vous pourrait avoir diverses scientifique des périphériques connectés à un rack de Pc et iphone, et de nouveau la "température" des valeurs pourrait arriver très souvent .... des dizaines de fois par image ... ou peut-être seulement quelques secondes.
Alors que faites-vous avec les valeurs?
Il ne pouvait pas être plus simple.
De l'arrivée-les valeurs de fil, tout ce que vous faire est de ................. attendez qu'il ............. définir une variable dans le composant!!
WTF? Tout ce que vous faites est définir une variable? Qui est-ce? Comment peut-il être aussi simple que cela?
C'est l'une de ces situations inhabituelles:
Grande partie de l'écriture sur des fils dans l'Unité est juste absolument mauvais. Ce n'est pas comme il a "une erreur" ou "quelque chose qui doit être corrigée". Il est "totalement faux": le paradigme de base de niveau.
Étonnamment, l'approche actuelle est ridiculement simple.
C'est tellement simple que vous pouvez penser que vous faites quelque chose de mal.
Ont donc la variable ...
Ensemble de la "arrivant fil" ...
Honnêtement que c'est.
Essentiellement, pour être le plus grand expert au threading "dans l'Unité" - qui est, bien évidemment, en fonction de la trame - il n'y a rien de plus à faire que ci-dessus.
Et à chaque fois que
ShowThermoValue
est appelée à chaque frame ...................... il suffit d'afficher cette valeur!Vraiment, c'est ça!
Vous êtes tout simplement de l'affichage de la "dernière" de la valeur.
latestValue peut-être une fois, deux fois, dix fois ou cent fois celle de l'image ............ mais, il vous suffit d'affichage,quelle que soit la valeur lorsque
ShowThermoValue
exécute le cadre!Quoi d'autre pourriez-vous afficher?
Le thermomètre est mise à jour à 60fps sur l'écran. Note de bas de page 2
C'est réellement facile. C'est aussi simple que cela. Surprenant mais vrai.
Parfois l'expérience de filetage programmeurs obtenir dans un noeud avec un cadre basé sur le système, parce que: dans un cadre basé sur le système de la plupart des considérations de verrouillage et de l'hippodrome ... n'existent pas sur le plan conceptuel.
Dans une trame de base du système, les éléments de jeu devraient être purement et simplement de l'affichage ou de comportement basé sur une certaine "valeur actuelle", qui est défini quelque part. Si vous avez des infos provenant d'autres threads, venez de définir ces valeurs - fait.
Vous ne peut pas véritablement "parler pour le thread principal" dans l'Unité, parce que le thread principal ............. est basé sur le cadre!
Mettre de côté les problèmes de threading, un système continu ne peut pas véritablement parler de un cadre-système de paradigme.
Plus de blocage, le blocage de la piste de course et les questions sont inexistante dans le cadre du paradigme basé sur parce que: si vous avez la latestValue dix fois, un million de fois, un milliard de fois, dans un cadre particulier .. que pouvez-vous faire? .. vous pouvez uniquement afficher une valeur!
Penser à un bon vieux film plastique. Littéralement, vous avez juste ...... un cadre, et c'est tout. Si vous avez la latestValue d'un trillion de fois dans un cadre particulier, ShowThermoValue affichera simplement (pour cette 60e de seconde), une valeur qu'elle saisit lorsqu'il est exécuté.
Tout ce que vous faire est: laissez-les dans un endroit, qui, à l'image de paradigme du système d'utilisation de cette image si elle veut.
C'est en un mot.
Ainsi, la plupart des "problèmes de threading" disparaître dans l'Unité.
Tout ce que vous pouvez faire de
autres threads de calcul ou
de plugin fils,
est juste "drop-off valeurs" dont le jeu peut utiliser.
Que c'est!
Notes de bas de page
1 Comment pourriez-vous? Comme une expérience de pensée, d'oublier le problème que vous êtes sur un autre thread. ShowThermoValue est exécuté une seule fois une image par l'image du moteur. Vous ne pouvez pas "call" de façon significative. Contrairement à la normale OO logiciel, vous ne pouvez pas, dire, instancier une instance de la classe (un Composant?? de sens) et exécuter cette fonction - qui est complètement dénuée de sens.
En "normal" fileté de programmation, les threads peuvent parler en arrière et en avant et ainsi de suite, et en faisant cela vous avez des préoccupations au sujet de verrouillage, l'hippodrome et ainsi de suite. Mais c'est tout sens dans un ECS, en fonction de la trame, d'un système. Il n'y a rien à "parler".
Disons que l'Unité était en fait multithread!!!! Si l'Unité gars ont tous à faire fonctionner le moteur dans un multithread. Pas que ça ferait une différence - vous ne pouvez pas obtenir "à" ShowThermoValue de manière significative! C'est un Composant qui le châssis moteur s'exécute une fois, un cadre.
Donc NewValueArrives n'est pas n'importe où - c'est une fonction de classe!
2 je me réfère à l'arrivée-les valeurs de fil" ... en fait! NewValueArrives peuvent, ou ne peuvent pas s'exécuter sur le thread principal!!!! Il peut s'exécuter sur le fil du plugin, ou sur un autre thread! Il peut effectivement être complètement seul thread par le temps de vous traiter avec le NewValueArrives appel! Il n'a tout simplement pas d'importance! Ce que vous faites, et tout ce que vous pouvez faire, dans un cadre à base de paradigme, c'est "congés autour de la pose" les informations que les Composants tels que ShowThermoValue, peut utiliser, comme ils l'entendent.
OriginalL'auteur Fattie
J'ai été en utilisant cette solution à ce problème. Créer un script avec ce code et de l'attacher à un Objet de Jeu:
Puis, quand vous avez besoin d'appeler quelque chose sur le sujet principal et l'accès à l'Unité de l'API de toute autre fonction de votre application:
OriginalL'auteur Pelayo Méndez
J'ai toujours le faire. J'espère que ça va vous aider trop.
OriginalL'auteur Bhavin Panara