【Unity】线程关闭方法

1 前言

        本文将介绍Unity中的线程关闭方法,并分析常见关闭方法中存在的问题。

2 常见线程关闭方法

        程序中常常有一些包含无限循环的线程存在,所以也需要有对应的关闭方法。线程的关闭方式通常有三种方法:

  1. 将线程设置为后台线程,主线程结束时后台线线程自动关闭。(无法使用)
  2. 调用Abort()函数终止线程。(不推荐)
  3. 使用bool变量控制线程结束循环,进而结束。(推荐)

上面已经标识了是否推荐,后面将对这三种方法进行说明。

2.1 后台线程

什么是后台线程?

        线程分为前台线程和后台线程,当我们使用new Thread创建一个线程后,其默认为前台线程,之后通过设置线程参数IsBackground = true,可将线程设置为后台线程。
        在进程关闭时,若前台线程没有结束,进程就无法结束,进程必须等待前台线程执行完毕再结束。当前台线程执行完毕,进程结束,此时若有后台线程未结束,则会直接终止后台线程。 
        但是在Unity中,这种方法并不适用。当我们创建一个执行无限循环的后台线程,之后再关闭进程,会发现线程无法终止。

代码:

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!");
        }
    }
}

演示:

可以发现在关闭运行后,线程仍然存活,在控制台持续输出内容。因此,该方法不可用。

        PS:当然这是在编辑器中的情况,打包后运行,然后退出程序会不会终止后台线程,我并不确定。各位感兴趣的话可以去测试下,但无论如何靠结束程序来终止线程的方法都不太提倡,既然是我们自己开的线程,就要由我们自己关闭。

2.2 Abort函数

        用于终止线程的函数,可通过线程自身调用。        

2.2.1 Abort函数的问题

        调用线程的Abort函数可以直接终止线程,多好的函数,然而!调用Abort函数并不一定会终止线程,也可能会抛出异常(概率抽奖)。

代码:

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();
        }
    }
}

演示(成功):

演示(失败):

PS:

  1. abort不是立刻关闭线程,如果其后紧跟线程状态输出语句,会发现,线程状态还是isAlive,有一个时间间隔,状态才改变。
  2. 在抛出异常后,后续再次执行Abort函数,无效,既不终止线程也不抛出异常。

2.2.2 问题讨论

        根据抛出异常的内容,可推测出“Abort无法终止线程的原因是其与线程内的执行内容发生了冲突”。接下来我们针对这个推测进行一些测试:

1、如果线程处于Sleep状态,是否可以Abort终止?

2、如果while(true)中无内容,是否可以Abort终止?

3、如果是线程自己执行Abort,是否可以Abort终止?

“测试”

1、如果线程处于Sleep状态,是否可以Abort终止?

代码:

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();
        }
    }
}

演示:

可以终止。

2、如果while(true)中无内容,是否可以Abort终止?

代码:

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();
        }
    }
}

演示:

可以终止。

3、如果是线程自己执行Abort,是否可以Abort终止?

代码:

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;
        }
    }
}

演示:

可以终止。

        PS:对于这种线程自己执行Abort的方法看似是一种解决方案,但我认为是有隐患的,前面也说了Abort不是立刻终止线程的,从执行完Abort函数到终止线程之间是有时间的,而在这段时间,线程会执行Abort函数后的内容,在执行过程中,可能会因为“终止线程”戛然而止,不是很安全。(不只是局限于线程自己调用Abort的情况,只是由此引出,只要调用Abort函数便有这种不安全性。不过若是线程自己调用Abort,那么可以紧接着阻塞线程,等待线程结束,也是个处理方法,但其他方式的Abort调用就不好说了。)

“结论”

由上述可得结论:

1、如果线程处于Sleep状态,是否可以Abort终止?可以。

2、如果while(true)中无内容,是否可以Abort终止?可以。

3、如果是线程自己执行Abort,是否可以Abort终止?可以。

        这三种情况本身都避免了Abort函数与线程本身执行内容的冲突,结果则是都可以使用Abort来终止线程。这证明了我们之前的推测。
        那么“使用Abort函数”这个方法能用吗?当然可以,但是要控制好在合适的时机调用Abort,防止冲突的发生,还要考虑逻辑戛然而止的情况,这自然是比较困难的,所以不推荐。

2.3 Bool变量控制

        使用一个Bool变量来控制线程的结束,这无疑是目前比较好的方法。我们在设计一个线程任务时,应该提前预留好结束线程的方式,并使用一个Bool变量来控制,把线程的结束逻辑掌握在我们自己手中。
        这种方式的好处是简单、好控制,且在结束线程的同时,能够保证线程执行逻辑的完整性,不会出现上文中所提到的“终止线程导致逻辑戛然而止的情况”。
        控制的方式有很多,具体该如何控制要根据线程执行的逻辑来决定。这里举个简单的例子:比如将无限循环的while(true){}中的true修改为一个变量来控制,需要退出时就将其置为false来退出循环。下面演示了这种方式。

代码:

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;
        }
    }
}

演示:

建议使用此方法控制线程结。

3 结束语

        综上所述,Unity线程如何关闭?

  1. 使用Abort函数终止线程。但要承担Abort函数与线程内执行内容冲突,进而导致抛出异常且无法终止线程的风险,且要考虑逻辑执行戛然而止的问题。
  2. 使用Bool变量控制线程结束。设计线程任务之初预留好结束逻辑,使用Bool变量控制线程结束。简单、好控制。(推荐)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: # Unity C# Unity C#(C Sharp)是一种基于.NET框架的面向对象编程语言,被广泛应用于开发Unity游戏引擎中的游戏、应用和其他交互性的体验项目。 与其他编程语言相比,Unity C#的特点在于它的简单易学、强大灵活和高效优化。Unity C#支持各种编程范式,包括过程式、面向对象、泛型、事件驱动和异步编程等,以满足开发者多变的需求。 在Unity中,C#主要用于编写游戏逻辑、控制游戏对象的行为和属性、实现玩家交互等功能。Unity C#支持许多现代编程特性,如LINQ、lambdas和扩展方法等,也为用户提供了许多额外的库和插件,如Unity GUI、Unity Networking和Unity Mobile Integration等,以满足不同平台的开发需求。 Unity C#Unity开发者社区中非常受欢迎,有许多开源项目和教程可供开发者学习和使用。同时,Unity C#的学习门槛相对较低,对于初学者来说非常友好,也是一种获得Unity游戏引擎开发技能的不错选择。 ### 回答2: # Unity C# Unity C#是用于编写Unity游戏引擎的一种脚本语言,类似于Java和C++。它支持面向对象编程和动态编译,并且具有良好的可读性和兼容性。Unity C#可以让开发者更方便地管理游戏对象,场景组件和材质贴图等游戏元素,使游戏的开发更加高效和简单。 使用Unity C#对游戏开发者而言有许多优势。首先,Unity C#不需要开发者考虑内存管理问题,因为Unity引擎自带内存管理。其次,Unity C#有常用的类库和工具,使得游戏开发者可以直接使用这些库和工具,而不需要单独编写。此外,Unity C#的性能不错,可以满足大多数游戏开发者的需求。 总的来说,Unity C#是一种方便简单的脚本语言,它可以加快游戏开发过程,减少开发者的心理负担。 ### 回答3: # Unity C#是什么? Unity C#是一种编程语言,是Unity引擎中广泛使用的编程语言。C#是一种高级的、经过现代化编程理念优化的语言,它的灵活性和可扩展性使它成为了很多程序员的首选语言之一。Unity C#的特点是简单易学、功能强大、代码可重用、快速开发和可跨平台编译等。 # Unity C#的作用? Unity C#Unity引擎中主要用于编写游戏的逻辑操作、动画、玩家输入、音效、物理交互等。Unity C#还可以用于制作游戏的菜单、UI、背包系统、任务系统等各种功能,能够为游戏带来更多的乐趣和便利。 # Unity C#的优点 Unity C#有很多优点,其中包括: 1. 易于学习:C#语言简单易懂,不需要特别高的专业技能,初学者通过快速入门后,即可快速掌握。 2. 功能强大:C#具有面向对象编程优势,可以进行对象抽象,也可以轻松进行多线程操作。 3. 模块化、可重用:C#编程语言具有良好的模块化特性,代码可以进行复用,能够提高编程效率。 4. 跨平台:Unity C#在不同平台之间的兼容性和可移植性很好,可以轻松打开任何支持Unity引擎的平台。 # 总结 Unity C#Unity游戏引擎中最常用的编程语言之一,它的简单易学、功能强大、代码可重用、快速开发和可跨平台编译等优点,使得C#语言成为众多游戏开发者的首选语言之一。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值