【Unity】Thread shutdown method

1 Introduction

        This article will introduce the thread shutdown method in Unity and analyze the problems in common shutdown methods.

2 Common thread shutdown methods

        There are often threads containing infinite loops in programs, so there are also corresponding shutdown methods. There are usually three methods for closing threads:

  1. Set the thread as a background thread, and the background thread will automatically close when the main thread ends. (not available)
  2. Call the Abort() function to terminate the thread. (Not recommended)
  3. Use bool variables to control the thread to end the loop and then end it. (recommend)

Whether it is recommended or not has been marked above, and these three methods will be explained later.

2.1 Background thread

What is a background thread?

        Threads are divided into foreground threads and background threads. When we use new Thread to create a thread, it defaults to the foreground thread. Later, by setting the thread parameter IsBackground = true, the thread can be set to a background thread.
        When the process is closed, if the foreground thread has not ended, the process cannot end. The process must wait for the foreground thread to finish executing before ending. When the foreground thread finishes executing, the process ends. If any background thread has not ended at this time, the background thread will be terminated directly. 
        But in Unity, this method does not apply. When we create a background thread that executes an infinite loop and then close the process, we will find that the thread cannot be terminated.

Code:

using System.Threading;
using UnityEngine;

public class N_002_ThreadTest : MonoBehaviour
{
    //定义线程
    private Thread th1;

    private void Start()
    {
        //创建线程
        th1 = new Thread(test1);
        //设置为后台线程
        th1.IsBackground = true;
        //开启线程
        th1.Start();
    }

    /// <summary>
    /// th1线程处理函数
    /// </summary>
    void test1()
    {
        //持续打印输出
        while (true)
        {
            Debug.Log("Thead Log!");
        }
    }
}

Demo:

It can be found that after shutting down the operation, the thread is still alive and continues to output content on the console. Therefore, this method is not available.

        PS: Of course, this is the case in the editor. After packaging and running, then exiting the program will terminate the background thread, I am not sure. If you are interested, you can test it, but in any case, the method of terminating the thread by ending the program is not recommended. Since the thread is opened by ourselves, we must close it ourselves.

2.2 Abort function

        The function used to terminate the thread can be called by the thread itself.        

2.2.1 Problems with the Abort function

        ​​​​Calling the thread's Abort function can directly terminate the thread. What a great function, however! Calling the Abort function does not necessarily terminate the thread, but may also throw an exception (probability lottery).

Code:

using System;
using System.Threading;
using UnityEngine;

public class N_002_ThreadTest : MonoBehaviour
{
    //定义线程
    private Thread th1;

    private void Start()
    {
        //创建线程
        th1 = new Thread(test1);
        //设置为后台线程
        th1.IsBackground = true;
        //开启线程
        th1.Start();
    }

    /// <summary>
    /// th1线程处理函数
    /// </summary>
    void test1()
    {
        //持续打印输出
        while (true)
        {
            Debug.Log("Thead Log!");
        }
    }

    //绘制UI
    private void OnGUI()
    {
        //绘制按钮,Abort终止线程th1
        if (GUI.Button(new Rect(120, 10, 80, 20), "Abort th1"))
        {
            th1.Abort();
        }
    }
}

Demo (successful):

Demo (failed):

PS:

  1. abort does not close the thread immediately. If it is followed by the thread status output statement, you will find that the thread status is still isAlive. There is a time interval before the status changes.
  2. After an exception is thrown, executing the Abort function again is ineffective. It neither terminates the thread nor throws an exception.

2.2.2 Problem discussion

        Based on the content of the exception thrown, it can be inferred that "the reason why Abort cannot terminate the thread is that it conflicts with the execution content in the thread." Next we conduct some tests on this speculation:

1. If the thread is in Sleep state, can it be terminated by Abort?

2. If there is no content in while(true), can it be terminated by Abort?

3. If the thread executes Abort by itself, can Abort terminate it?

"test"

1. If the thread is in Sleep state, can it be terminated by Abort?

Code:

using System;
using System.Threading;
using UnityEngine;

public class N_002_ThreadTest : MonoBehaviour
{
    //定义线程
    private Thread th1;

    private void Start()
    {
        //创建线程
        th1 = new Thread(test1);
        //设置为后台线程
        th1.IsBackground = true;
        //开启线程
        th1.Start();
    }

    private void Update()
    {
        //持续输出线程状态
        Debug.Log("th1线程存活状态:" + th1.IsAlive);
    }

    /// <summary>
    /// th1线程处理函数
    /// </summary>
    void test1()
    {
        //开局先睡个10s
        Thread.Sleep(10000);

        //持续打印输出
        while (true)
        {
            Debug.Log("Thead Log!");
        }
    }

    //绘制UI
    private void OnGUI()
    {
        //绘制按钮,Abort终止线程th1
        if (GUI.Button(new Rect(120, 10, 80, 20), "Abort th1"))
        {
            th1.Abort();
        }
    }
}

Demo:

Can be terminated.

2. If there is no content in while(true), can it be terminated by Abort?

Code:

using System;
using System.Threading;
using UnityEngine;

public class N_002_ThreadTest : MonoBehaviour
{
    //定义线程
    private Thread th1;

    private void Start()
    {
        //创建线程
        th1 = new Thread(test1);
        //设置为后台线程
        th1.IsBackground = true;
        //开启线程
        th1.Start();
    }

    private void Update()
    {
        //持续输出线程状态
        Debug.Log("th1线程存活状态:" + th1.IsAlive);
    }

    /// <summary>
    /// th1线程处理函数
    /// </summary>
    void test1()
    {
        //持续循环
        while (true)
        {
            //无
        }
    }

    //绘制UI
    private void OnGUI()
    {
        //绘制按钮,Abort终止线程th1
        if (GUI.Button(new Rect(120, 10, 80, 20), "Abort th1"))
        {
            th1.Abort();
        }
    }
}

Demo:

Can be terminated.

3. If the thread executes Abort by itself, can Abort terminate it?

Code:

using System;
using System.Threading;
using UnityEngine;

public class N_002_ThreadTest : MonoBehaviour
{
    //定义线程
    private Thread th1;

    //状态控制
    private bool isOver_th1 = false;//th1终止状态

    private void Start()
    {
        //创建线程
        th1 = new Thread(test1);
        //设置为后台线程
        th1.IsBackground = true;
        //开启线程
        th1.Start();
    }

    private void Update()
    {
        //持续输出线程状态
        Debug.Log("th1线程存活状态:" + th1.IsAlive);
    }

    /// <summary>
    /// th1线程处理函数
    /// </summary>
    void test1()
    {
        //持续打印输出
        while (true)
        {
            //若状态改为终止状态,则自行Abort终止
            if (isOver_th1)
            {
                th1.Abort();
            }
            Debug.Log("Thead Log!");
        }
    }

    //绘制UI
    private void OnGUI()
    {
        //绘制按钮,修改线程th1终止状态
        if (GUI.Button(new Rect(120, 10, 80, 20), "Abort th1"))
        {
            isOver_th1 = true;
        }
    }
}

Demo:

Can be terminated.

        PS: This method of executing Abort by the thread itself seems to be a solution, but I think it has hidden dangers. As mentioned earlier, Abort does not terminate the thread immediately. There is a gap between the execution of the Abort function and the termination of the thread. time, and during this period, the thread will execute the content after the Abort function. During the execution process, it may stop abruptly due to "terminating the thread", which is not very safe. (It is not limited to the situation where the thread itself calls Abort, but it also leads to the insecurity as long as the Abort function is called. However, if the thread itself calls Abort, then it can block the thread and wait for the thread to end, which is also a solution. method, but it’s hard to say how to call Abort in other ways.)

"in conclusion"

It can be concluded from the above:

1. If the thread is in Sleep state, can it be terminated by Abort? Can.

2. If there is no content in while(true), can it be terminated by Abort? Can.

3. If the thread executes Abort by itself, can Abort terminate it? Can.

        These three situations themselves avoid the conflict between the Abort function and the execution content of the thread itself. As a result, Abort can be used to terminate the thread. This proves our previous speculation.
        So can the method of "using the Abort function" be used? Of course it is possible, but it is naturally difficult to control the calling of Abort at the right time to prevent conflicts and consider the situation where the logic stops abruptly, so it is not recommended.

2.3 Bool variable control

        Using a Bool variable to control the end of the thread is undoubtedly a better method at present. When we design a thread task, we should reserve the way to end the thread in advance and use a Bool variable to control it, so that the thread ending logic is in our own hands.
        The advantage of this method is that it is simple and easy to control, and while terminating the thread, it can ensure the integrity of the thread execution logic, and there will be no "thread termination leading to logic" mentioned above. A situation that came to an abrupt end”.
        There are many ways to control. The specific method of control depends on the logic of thread execution. Here is a simple example: For example, change true in the infinite loop while(true){} to a variable to control. When you need to exit, set it to false to exit the loop. This approach is demonstrated below.

Code:

using System;
using System.Threading;
using UnityEngine;

public class N_002_ThreadTest : MonoBehaviour
{
    //定义线程
    private Thread th1;

    //状态控制
    private bool isRunning_t1 = true;//th1运行状态

    private void Start()
    {
        //创建线程
        th1 = new Thread(test1);
        //设置为后台线程
        th1.IsBackground = true;
        //开启线程
        th1.Start();
    }

    private void Update()
    {
        //持续输出线程状态
        Debug.Log("th1线程存活状态:" + th1.IsAlive);
    }

    /// <summary>
    /// th1线程处理函数
    /// </summary>
    void test1()
    {
        //若线程运行状态,则持续打印输出
        while (isRunning_t1)
        {
            Debug.Log("Thead Log!");
        }

        //结束时离开while循环,然后执行
        Debug.Log("线程th1结束了!");
    }

    //绘制UI
    private void OnGUI()
    {
        //绘制按钮,修改线程th1运行状态
        if (GUI.Button(new Rect(120, 10, 80, 20), "End th1"))
        {
            isRunning_t1 = false;
        }
    }
}

Demo:

It is recommended to use this method to control thread knots.

3 Conclusion

        In summary, how to close the Unity thread?

  1. Use the Abort function to terminate the thread. However, you have to bear the risk that the Abort function will conflict with the execution content in the thread, causing an exception to be thrown and the thread to be unable to be terminated, and you have to consider the problem of the logic execution ending abruptly.
  2. Use Bool variables to control the end of the thread. Reserve the end logic at the beginning of designing the thread task, and use Bool variables to control the end of the thread. Simple and easy to control. (recommend)

Guess you like

Origin blog.csdn.net/Davidorzs/article/details/134216164