Unity3D -Thread多執行緒,Queue佇列,lock關鍵字
阿新 • • 發佈:2021-01-20
例一:
1.Thread 多執行緒
Unity裡一般用於Socket連線,開一條執行緒接訊息。
2.Queue佇列
物件的先進先出集合,可以規定特定型別的佇列集合,也可以什麼型別都存入佇列。
Queue aaa = new Queue(); Queue<int> aaa = new Queue<int>(); 都是可以的。
3.lock 關鍵字
主要用於處理併發問題、鎖定獨佔物件。鎖定的必須是引用型別!
先寫一個執行緒類,不用繼承MonoBehaviour。
public class XianCheng { public Thread ThreadOne; public Thread ThreadTwo; public Queue<int> queue = new Queue<int>(); //先進先出佇列 public void StartXianCheng() { //執行緒1 ThreadOne = new Thread(Count); //執行緒開始方法 ThreadOne.IsBackground = true; //後臺執行緒會隨著主執行緒結束退出 //ThreadOne.Name = "Xiancheng1"; //執行緒名字 ThreadOne.Start(); //開始執行緒 //執行緒2 ThreadTwo = new Thread(Count); ThreadTwo.Start(); } public void Count() { //這裡可以註釋掉lock來測試 lock (queue) //鎖定佇列,必須等待一條執行緒訪問完成後,別的執行緒才能使用 { queue.Enqueue(1); //入隊 // queue.Dequeue(); //出隊,返回佇列開始處的物件,並且刪除它! Thread.Sleep(1000); //執行緒休眠毫秒數 // ThreadOne.Suspend(); //暫停執行緒 // ThreadOne.Resume(); //繼續執行緒 } } }
再寫一個類,很簡單。
public class NewBehaviourScript : MonoBehaviour { XianCheng xiancheng; void Start () { xiancheng = new XianCheng(); xiancheng.StartXianCheng(); } void Update () { Debug.Log(xiancheng.queue.Count); //lock的話,列印先1後2,不lock直接2,因為兩個執行緒同時使用了佇列。 } void OnApplicationQuit() { xiancheng.ThreadTwo.Abort(); //終止執行緒1 xiancheng.ThreadOne.Abort(); //終止執行緒2 } }
例二:
using UnityEngine; using System.Collections; using UnityEngine.UI; public class QueueExample : MonoBehaviour { public Queue queue; public Text queueCount; public Text queueContent; public Text queuePeek; void Start() { queue = new Queue(); } void Update() { if (queue.Count > 0) { queuePeek.text = "queuePeek : " + queue.Peek().ToString(); } else { queuePeek.text = "queuePeek : "; } //增加元素 if (Input.GetKeyDown(KeyCode.A)) { InsetTime(); showQueue(); } //減去元素 if (Input.GetKeyDown(KeyCode.D)) { if (queue.Count > 0) { Debug.Log(queue.Dequeue()); showQueue(); } } //清除佇列所有元素 if (Input.GetKeyDown(KeyCode.C)) { queue.Clear(); showQueue(); } queueCount.text = "queueCount : " + queue.Count.ToString(); } void InsetTime() { queue.Enqueue(Time.time); } void showQueue() { queueContent.text = "queueContent : "; foreach (float value in queue) { queueContent.text += value.ToString() + " | "; } } }
例三:
//用平均值的方法平滑陀螺儀曲線,實現思想簡單描述如下
Queue<Quaternion> averageList;
averageList.Enqueue (Input.gyro.attitude);
if (averageList.Count > 240)
averageList.Dequeue ();
foreach (Quaternion singleRotation in averageList)
{
//分離,重組Quaternion,獲得平均值averageRotation
}
//通過插值貼回給攝像頭
transform.localRotation = Quaternion.Slerp(transform.localRotation, averageRotation, Time.deltaTime* 4f);
Queue的基本功能有插入、提取和檢查操作。可以用來如排隊,計時等線性相關的問題。通過插入,提取,檢查,清除等操作了解queue的執行,
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class QueueExample : MonoBehaviour
{
public Queue queue;
public Text queueCount;
public Text queueContent;
public Text queuePeek;
void Start()
{
queue = new Queue();
}
void Update()
{
if (queue.Count > 0)
{
queuePeek.text = "queuePeek : " + queue.Peek().ToString();
}
else
{
queuePeek.text = "queuePeek : ";
}
//增加元素
if (Input.GetKeyDown(KeyCode.A))
{
InsetTime();
showQueue();
}
//減去元素
if (Input.GetKeyDown(KeyCode.D))
{
if (queue.Count > 0)
{
Debug.Log(queue.Dequeue());
showQueue();
}
}
//清除佇列所有元素
if (Input.GetKeyDown(KeyCode.C))
{
queue.Clear();
showQueue();
}
queueCount.text = "queueCount : " + queue.Count.ToString();
}
void InsetTime()
{
queue.Enqueue(Time.time);
}
void showQueue()
{
queueContent.text = "queueContent : ";
foreach (float value in queue)
{
queueContent.text += value.ToString() + " | ";
}
}
}
例四:訊息廣播中心
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using System;
public class GameEvent{ }
public class EventQueueSystem : MonoSingleton<EventQueueSystem>
{
public delegate void EventDelegate<T>(T e) where T : GameEvent;
private delegate void InternalEventDelegate(GameEvent e);
private Dictionary<Type, InternalEventDelegate> delegates = new Dictionary<Type, InternalEventDelegate>();
private Dictionary<Delegate, InternalEventDelegate> delegateLookup = new Dictionary<Delegate, InternalEventDelegate>();
private Dictionary<InternalEventDelegate, Delegate> delegateLookOnce = new Dictionary<InternalEventDelegate, Delegate>();
private Queue eventQueue = new Queue();
public bool bLimitQueueProcessing = false;
public float limitQueueTime = 0.1f;
//註冊偵聽事件(持續)
public static void AddListener<T>(EventDelegate<T> del) where T : GameEvent
{
Instance.AddDelegate(del);
}
//註冊偵聽事件(一次)
public static void AddListenerOnce<T>(EventDelegate<T> del) where T : GameEvent
{
var result = Instance.AddDelegate(del);
if (result != null)
Instance.delegateLookOnce[result] = del;
}
//判定偵聽事件是否存在
public static bool HasListener<T>(EventDelegate<T> del) where T : GameEvent
{
return Instance.delegateLookup.ContainsKey(del);
}
//移除偵聽事件
public static void RemoveListener<T>(EventDelegate<T> del) where T : GameEvent
{
if (Instance == null)
return;
if (Instance.delegateLookup.TryGetValue(del, out InternalEventDelegate eventDelegate))
{
if (Instance.delegates.TryGetValue(typeof(T), out InternalEventDelegate temp))
{
temp -= eventDelegate;
if (temp == null)
Instance.delegates.Remove(typeof(T));
else
Instance.delegates[typeof(T)] = temp;
}
Instance.delegateLookup.Remove(del);
}
}
public static void RemoveAll()
{
if (Instance != null)
{
Instance.delegates.Clear();
Instance.delegateLookup.Clear();
Instance.delegateLookOnce.Clear();
}
}
private InternalEventDelegate AddDelegate<T>(EventDelegate<T> del) where T : GameEvent
{
if (delegateLookup.ContainsKey(del))
return null;
void eventDelegate(GameEvent e) => del((T)e);
delegateLookup[del] = eventDelegate;
if (delegates.TryGetValue(typeof(T), out InternalEventDelegate temp))
delegates[typeof(T)] = temp += eventDelegate;
else
delegates[typeof(T)] = eventDelegate;
return eventDelegate;
}
//單個事件觸發
private static void TriggerEvent(GameEvent e)
{
var type = e.GetType();
if(Instance.delegates.TryGetValue(type,out InternalEventDelegate eventDelegate))
{
eventDelegate.Invoke(e);
//移除單一偵聽
foreach(InternalEventDelegate item in Instance.delegates[type].GetInvocationList())
{
if (Instance.delegateLookOnce.TryGetValue(item,out Delegate temp))
{
Instance.delegates[type] -= item;
if (Instance.delegates[type] == null)
Instance.delegates.Remove(type);
Instance.delegateLookup.Remove(temp);
Instance.delegateLookOnce.Remove(item);
}
}
}
}
//外部呼叫的推入事件佇列介面
public static void QueueEvent(GameEvent e)
{
if (!Instance.delegates.ContainsKey(e.GetType()))
return;
Instance.eventQueue.Enqueue(e);
}
//事件佇列觸發處理
void Update()
{
float timer = 0.0f;
while (eventQueue.Count > 0)
{
if (bLimitQueueProcessing)
if (timer > limitQueueTime)
return;
var e = eventQueue.Dequeue() as GameEvent;
TriggerEvent(e);
if (bLimitQueueProcessing)
timer += Time.deltaTime;
}
}
private void OnApplicationQuit()
{
RemoveAll();
eventQueue.Clear();
}
}