在Mono .Net线程中,线程是否缠住,还是?

时间:2019-01-17 18:31:48

标签: c# c .net multithreading unity3d

这是在Unity / Mono中,但是在任何.Net中……

想象一下这样的代码

using System.Threading;
using System.Runtime.InteropServices;

public class Example: MonoBehaviour {

    [DllImport("__Internal")] private static extern void long_function();
    [DllImport("__Internal")] private static extern void short_function();
    public Thread happyThread;
    public void Test() {

        happyThread = new Thread(LongTest);
        happyThread.Start();
    }
    private void LongTest() { long_function(); }
    private void ShortTest() { short_function(); }
}

我们运行Test,因此从C库启动了long_function。它在另一个线程上启动。 (“ happyThread”)

说运行需要60秒。

  1. 在那之后,happyThread不再存在了吗?还是在示例范围内?还是可以保留它或其他东西?

  2. 比方说,我们知道long_function完成了。然后,我要呼叫ShortTest,因此要呼叫short_function。你能做这样的事吗?。

我们之前做过

        happyThread = new Thread(LongTest);

我们现在可以将线程的“内容”“更改”为

        happyThread.newStuff( ShortTest());
        happyThread.StartAgain();

还是那个愚蠢而毫无意义的东西?

  1. 仅在另一个新线程上再次启动ShortTest吗?

  2. 说该库具有一个简单的 global 变量int k ...

因此,TBC,内置于静态库的C文件在顶部看起来像这样:

// file happyLibrary.c Fattie(TM) 2019
#include <stdio.h>
#include <CoreFoundation/CoreFoundation.h>
int k = 7; // (NB you almost certainly want volatile here in real apps)
void long_function
{
    ...
  1. ...,其中long_function设置为42。实际上.... short_function以后也可以访问该值?要么?仅当我使用相同的线程或其他东西时?同样,k是一个全局全局变量。

  2. 如果您必须启动成千上万的小任务,如果重新使用happyThread可能会带来性能优势,并且可以重用'em ??

(我完全赞赏,long_function会一直保留在那里,并使用short_function概念提供对主线程的回调;但是,我想知道我在上面提出的问题。 -使用“线程?您可以再次进入它吗?”

1 个答案:

答案 0 :(得分:3)

  
      
  1. 在那段时间的尽头,happyThread不再存在了吗?还是在示例范围内?还是可以保留它或其他东西?
  2.   

在线程上调用的函数(在这种情况下为LongTest)完成后,线程的生命周期将结束。只要您在happyThread中有对该线程的引用,该线程仍然存在(您可以自己查看!happyThread.ManagedThreadId仍会返回该线程的ID,即使已完成该线程也是如此),但是它不能重新启动。您可以通过调用happyThread.ThreadState(此时将返回stopped)来检查线程的状态。

  

我们现在可以将线程的“内容”“更改”为

happyThread.newStuff( ShortTest());
happyThread.StartAgain();

不,您不能。您无法将新函数绑定到已终止的线程,并且如果尝试再次在其上调用happyThread.Start(),它将抛出ThreadStateException Thread has already been started.

  

我会只是在另一个新线程上再次启动ShortTest吗?

是的。您将必须在ShortTest上启动new Thread(ShortTest)(或者您可以将其添加到LongTest()方法的末尾。在线程上启动的任何新方法都将在该线程上运行)。但是,您可以在旧的happyThread上调用新线程。因此happyThread = new Thread(ShortTest())将很高兴再次启动!您甚至可以在第一个线程用完之前在happyThread上启动一个新线程。所以

Thread happyThread = new Thread(LongTest());//say this runs for 1 minute
happyThread.Start();
happyThread = new Thread(ShortTest());//this will start without a problem
happyThread.Start();

也会愉快地开始。但是请注意,这不应该真的完成。这将使您丢失对运行LongTest的线程的引用。 (尽管首先调用了LongTest,但如果该线程恰好触发了ShortTest,实际上它可能会首先开始运行...这确实很不理想,但只是想展示它 is < / em>。)

  

short_function还会在以后访问该值吗?

是的,我们假设int k是公共的和全局的,并且仅在主线程上运行。您可以将其值从long_function设置为42,然后根据需要在不同的 线程上从int k读取short_function的值。现在请注意,您必须谨慎设置/获取多个线程中的变量,以防止出现race conditions

但是,如果您在运行在单独线程上的方法中定义int k,则当线程死亡时,它将超出范围,就像在函数用完时在函数内部初始化的任何变量一样。 / p>

您可以使用volatile关键字来指示一个变量可能被多个线程修改。 Msdn docs

  

如果您必须启动不计其数的小任务...

如果您要启动/关闭许多线程,则可能要使用ThreadPools

  

您可以“重用”线程吗?您可以再次“加入”吗?

所以一切都归结为否。线程死亡后,将无法再次启动,有关该特定主题的信息,也请参见this SO post

但是,作为替代方案,您可以在应用程序运行期间保持线程处于活动状态,如果您知道要多次甚至连续调用它(例如,我使用它在后台保持TCP连接)必须始终可以访问)。可以这样做:

Void Start()
{
    Thread happyThread = new thread(() => KeepAlivethread(1000));//short, easy way to create a delegate so you can pass parameters to your thread aswell!
    happyThread.Start();
}

volatile bool keepThreadAlive = true;//volatile because it may be accessed from another thread

private void KeepAliveThread(int timeout)
{
    Debug.Log("Thread started with id: " + Thread.CurrentThread.ManagedThreadId); 
    while (keepThreadAlive)
    {
        //do something, maybe have an event that calls to ShortTest.
        Thread.Sleep(timeout);
    }
    Debug.Log("Thread terminating with id: " + Thread.CurrentThread.ManagedThreadId);
}

现在,该线程将继续在后台运行,直到您设置keepThreadAlive = false,之后该线程才正常终止。 (这样做可以不必thread.Abort(),这很不好!(更多信息请参见之前链接的SO帖子的答案)