[多线程] Thread

多线程

概述

单任务处理:一个任务完成后才能进行下一个任务。

多任务处理:CPU分时操作,每个任务看似同时运行。

进程

应用程序的一个运行实例,包含程序所需资源的内存区域,是操作系统进行资源分配的单元,进程隔离了正在执行的不同程序。(打开某一个软件,分配CPU,隔离其他软件)

优点:进程间相互独立,互不影响。

线程

进程中的一个执行单元(进程是程序边界,要靠线程执行程序,线程指向方法,执行完毕释放线程),是CPU分配时间片的单位,一个进程可以包含多个线程,且相互独立,共享当前进程所有资源。

优点:

  1. 并发执行,合理使用CPU资源
  2. 相同程序的线程共享堆内存。

缺点:

  1. 频繁创建/销毁线程增加性能开销。
  2. 访问共享资源可能造成冲突。
  3. 辅助线程不能访问Unity API。

注意事项

  1. Unity的API不能在辅助线程运行。
  2. Unity定义的基本结构(int,Vector3,Quaternion等)可以在辅助线程计算。
  3. Unity定义的基本类型的函数可以在分线程运行。

多线程

在单核系统的一个单位时间内,CPU只能运行单个线程,运行顺序取决于线程的优先级。如果在单位时间内线程未能完成执行,系统就会把线程的状态信息保存到线程的本地存储器(TLS) 中,以便下次执行时恢复执行。因为切换频密,所以多线程可被视作同时运行,而实际只是一个假象。

在多核系统的一个单位时间内,进程或线程可以在不同的CPU中运行,使得真正的并行处理。

适用性

耗时的任务,通过多线程可以并行处理。

一个程序完成多个任务,通过多个线程使用多核CPU来处理可以提升性能

线程实现

命名空间:System.Threading;

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;

public class ThreadDemo1 : MonoBehaviour
{
    private Thread thread;
    private void Start01()
    {
        //Func1();//同步调用  一次性完成0 1 2 3 4 ....

        //线程调用
        //thread = new Thread(Fun1);
        //thread.Start();
        //睡眠一秒 期间没有CPU调度 0 睡眠一秒,依次循环 1 2 3 4... 

        //thread = new Thread(Fun2);
        //thread.Start(5);
        //方法重载  参数object类型

        thread = new Thread(Fun4);
        thread.Start();

        //ThreadPool.QueueUserWorkItem(Fun3,null);
        //线程池开辟的线程无法设置前后台/优先级等
        //通过线程池开辟线程 不能Start启用
    }
    //thread.Start()  //无参
    private void Fun1()
    {
        for (int i = 0; i < 30; i++)
        {
            signal.WaitOne(3000);
            //整数  代表最长的等待时间
            Thread.Sleep(1000);
            print(i);
        }
    }
    ////thread.Start(5)  //有参
    private void Fun2(object o)
    {
        int count = (int)o;
        for (int i = 0; i < count; i++)
        {
            Thread.Sleep(1000);
            print(i);
        }
    }
    /// <summary>
    /// 对象池
    /// </summary>
    private void Fun3(object o)
    {
        //int[] arr = (int[])o;
        //int count = (int)o;
        for (int i = 0; i < 5; i++)
        {
            Thread.Sleep(1000);//模拟此时操作一分钟
            print(i);//主线程 卡   指的就是生命周期

        }
    }

    /// <summary>
    /// 死循环 怎么办
    /// </summary>
    private void Fun4()
    {
        int n = 0;
        while (true)
        {
            Thread.Sleep(1000);
            print(++n);
        }
    }
    /// <summary>
    /// 退出线程
    /// </summary>
    private void OnApplicationQuit()
    {
        //thread.Abort();
        //结束线程
        //主线程卡顿的情况  可以开辟新的线程
    }
    /// <summary>
    /// 信号灯
    /// </summary>
    private ManualResetEvent signal;

    private void Start()
    {
        //信号灯 绿灯行  红灯停
        signal = new ManualResetEvent(true);
        //true表示绿灯 false 表示红灯
        thread = new Thread(Fun1);
        thread.Start();
    }
    private void OnGUI()
    {
        if (GUILayout.Button("线程暂停"))
        {
            signal.Reset();
        }
        if (GUILayout.Button("线程继续"))
        {
            signal.Set();
        }
    }
}
View Code

Thread 

  1. 创建线程: 创建Thread一个对象,分配一个线程作方法 

             Thread thread = new Thread(工方法);

  1. 线程Start方法。

             thread.Start();

  1. 终止线程:工作方法自然退出、线程终止。

             thread. Abort ();

ThreadPool

在频繁创建和销毁线程时使用线程池技术,可以有效减少时间以及系统资源的开销

ThreadPool.QueueUserWorkItem(工作方法);

/后台线程

前台线程:程序必须等待所有前台线程结束后才能退出。(只要有一个前台线程未退出,进程就不会终止!即说的就是程序不会关闭!)[Thread创建的线程默认前台线程]

后台线程:程序不考虑后台线程,后台线程随程序退出而结束。[ThreadPool创建的线程默认后台线程]

备注Unity程序退出后,前台线程也随即关闭。

新建的子线程可以是前台线程或者后台线程,前台线程必须全部执行完,即使主线程关闭掉,这时进程仍然存活。

线程状态

启动状态 Unstarted创建线程对象

运行状态Running执行绑定的方法。

等待睡眠阻塞状态 WaitSleepJoin:暂时停止执行资源交给其他线程使用

终止状态 Stopped线程销毁

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using UnityEngine.UI;
using System.Threading;


public class ThreadDemo : MonoBehaviour
{
    private int second = 60;
    private Text text;
    private void Start()
    {
        text = GetComponent<Text>();
        Thread thread = new Thread(Timer);
        thread.Start();
    }
    private void Update()
    {
        if (action!=null)
        {
            action();
            action = null;
        }
    }
    private void Timer()
    {
        while (second>0)
        {
            Thread.Sleep(1000);//睡一会  期间没有CPU的调度

            action = () =>
            {
                second--;
                text.text = string.Format("{0:d2}:{1:d2}", second / 60, second % 60);
            };
        }   
    }
    private Action action;
}

线程同步

需要同步的原因: 

多个线程同一时刻访问共享资源(线程共享实例变量,静态变量)由于每个线程都不知道其他线程的操作结果将产生不可预知的数据损坏。 

步:

线程之间相互等待排队执行

何同步:

需要同步的代码用关键字lock定,锁定后该代码对于线程来讲是独占使用的。当其他线程试图进入被锁定的临界区时只能等待解锁后才可访问。锁定代码时是排访问的,所以叫线程同步。 

 

Lock锁原理:

对象在堆中的分配:实例成员、同步块索引 (默认索引-1)类型指针(指向类型对象)。      

对象上锁后,同步索引块会指向同步块数组中的一个对象。

当其他对象执行lock的时候会等待该对象同步索引设置为-1

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;

public class Bank
{
    public static int Money = 1;
    public static object o = new object();
    //必须使用引用类型
    //优先使用object
    public static void Get(int val)
    {
        lock (o)//-1   0  只有是-1的时候  锁打开  否则锁关闭
        {          //同步块索引 类型对象指针
                   //共享读  独占写
                   //枷锁(对象)  流程
            if (Money >= val)
            {
                //线程冲突 0  -1   -2  如何解决???加锁
                Thread.Sleep(1000);
                Money -= val;
                Debug.Log("取钱成功!余额:" + Money);
            }
            else
            {
                Debug.Log("取钱失败!余额:" + Money);
            }
            //线程离开代码块  索引块  设置为-1
        }
    }
}


public class ThreadDemo2 : MonoBehaviour
{
    private void Start()
    {
        //Bank.Get(1);  //同步调用  排队
        ThreadPool.QueueUserWorkItem(o =>
        {
            Bank.Get(1);
        });
        ////线程调用(多线程)  不排队
    }
}

猜你喜欢

转载自www.cnblogs.com/ASsss/p/10438885.html