Корректное завершение потока

Сеть в Unity3D

Корректное завершение потока

Сообщение soleren 14 июн 2017, 11:52

Добрый день,не могу разобраться с двумя вопросами,а именно корректное отключение клиента в редакторе,скорее всего по причине незакрытого потока.как правильно закрыть поток ума неприложу,то что работает в консоли не работает в юнити.
И второй это обмен сообщениями между потоками.

Chat.cs
Синтаксис:
Используется csharp
using UnityEngine;
using System.Collections.Generic;
using UnityEngine.UI;
using System.Threading;
using System.Net.Sockets;
using System;
using System.Text;

public class Chat : MonoBehaviour {

    private InputField inputField;
    private Button sendButton;
    private Text chatText;
    private Button conDisconBtn;
    private GameObject[] chatObjects;
    public List<string> messages;
    private Client client;
    private Thread receiveThread;
    private bool isConnected;
    public Queue<string> m = new Queue<string>();
    // Use this for initialization
    void Start ()
    {
        messages = new List<string>();
        chatObjects = GameObject.FindGameObjectsWithTag("chat");
        inputField = GameObject.Find("InputField").GetComponent<InputField>();
        sendButton = GameObject.Find("Send").GetComponent<Button>();
        conDisconBtn = GameObject.Find("ConDiscon").GetComponent<Button>();
        chatText = GameObject.Find("Text").GetComponent<Text>();
        conDisconBtn.GetComponentInChildren<Text>().text = "Connect";
        //HideElements();
    }
       
    private void HideElements()
    {
        for (int i = 0; i < chatObjects.Length; i++)
            chatObjects[i].SetActive(false);
    }

    private void ShowElements()
    {
        for (int i = 0; i < chatObjects.Length; i++)
            chatObjects[i].SetActive(true);
       
    }

    public void Connect()
    {
        if (!isConnected)
        {
            client = new Client();
            client.Connect();
            print("Connection done!");
            isConnected = true;
            conDisconBtn.GetComponentInChildren<Text>().text = "Disconnect";
            //ShowElements();

            receiveThread = new Thread(client.ReceiveMessage);
            receiveThread.IsBackground = true;
            receiveThread.Start();
            print("Thread is running");
        }
        else
        { // при попытке отключения Unity виснет
            print("Thread is cloising");
            conDisconBtn.GetComponentInChildren<Text>().text = "Connect";
           receiveThread.Abort();
            receiveThread.Join();
            print(receiveThread.IsAlive);
            client.Disconnect();
        }  
    }
   
    public void sendMessage()
    {
        string message = inputField.text;
        client.SendMessage(message);
    }

    public void ReceiveMessage(string message)
    {
        print(message);
        messages.Add(message + "\n");  // unity вылетает при попытке записать из другого потока
        foreach (string m in messages)
            chatText.text = m;
    }
   
    void OnDestroy()
    {
        client.Disconnect();
    }
}
 


Client.cs
Синтаксис:
Используется csharp
using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;

class Client
{
    private const string host = "127.0.0.1";
    private const int port = 10000;
    private TcpClient client;
    private NetworkStream stream;
    private bool isReceiving;
    private Chat chat;

    public void Connect()
    {
        client = new TcpClient();
        try
        {
            client.Connect(host, port); //подключение клиента
            stream = client.GetStream(); // получаем поток
            isReceiving = true;
            chat = new Chat();
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
       
    }


    // отправка сообщений
    public void SendMessage(string message)
    {
        byte[] data = Encoding.Unicode.GetBytes(message);
        stream.Write(data, 0, data.Length);
    }


    // получение сообщений
    public void  ReceiveMessage()
    {
        while (isReceiving)
        {
            try
            {
                int bufSize = client.ReceiveBufferSize;
                byte[] data = new byte[bufSize]; // буфер для получаемых данных
                StringBuilder builder = new StringBuilder();
                int bytes = 0;

                do
                {
                    bytes = stream.Read(data, 0, data.Length);
                    String str = Encoding.Unicode.GetString(data, 0, data.Length).Trim('\0');
                    builder.Append(str);
                    Thread.Sleep(10);
                }
                while (stream.DataAvailable);
               
                string message = builder.ToString();
                chat.ReceiveMessage(message);
                chat.m.Enqueue(message);
            }
            catch (Exception ex)
            {
                Debug.Log("Подключение прервано!" + ex.ToString()); //соединение было прервано
                Disconnect();
            }
            Thread.Sleep(10);
        }
    }

    public void StopReceiving()
    {
        isReceiving = false;
    }

    public void Disconnect()
    {
        isReceiving = false;
        {
            stream.Close();//отключение потока
            stream.Dispose();
        }
           
        if (client != null)
        {
            client.Close();//отключение клиента
           
        }          
        Environment.Exit(0); //завершение процесса
    }

    ~Client()
    {
        if (stream != null)
            stream.Close();//отключение потока
        if (client != null)
            client.Close();//отключение клиента
    }
}
 
soleren
UNец
 
Сообщения: 1
Зарегистрирован: 14 июн 2017, 10:48

Re: Корректное завершение потока

Сообщение seaman 14 июн 2017, 12:58

Насколько я понял:
вызывает метод Join в объекте рабочего потока. Этот метод приводит к блокировке или ожиданию текущего потока до тех пор, пока не будет завершен поток, представляемый объектом. Следовательно, Join не возвращается до тех пор, пока не возвращается рабочий поток, таким образом завершая себя:

Т.е. Вы вешаете основной поток Юнити. По идее до того как receiveThreadне завершится. Однако т.к. Юнити весьма плохо поддерживает многопоточность - видимо вешается навсегда...
Вызывайте вместо этого корутину, в которой проверяйте receiveThread.IsAlive. Ну и когда receiveThread действительно завершится - делайте что нужно в основном потоке.
seaman
Адепт
 
Сообщения: 8352
Зарегистрирован: 24 янв 2011, 12:32
Откуда: Самара


Вернуться в Сеть

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 3