The biggest difference between the two is the scope: a mutex's scope is system-wide, whilst monitor's scope depends on the scope of the object you lock on. This means that with monitor, the widest scope you can get is generally application-wide.
So you would mostly use monitor to synchronise between threads running in an application, and use mutex to synchronise between different applications.
2)Monitor VS. lock
lock is just shortcut for Monitor.Enter with try + finally and Monitor.Exit. Use lock statement whenever it is enough - if you need something like TryEnter, you will have to use Monitor.
3)Semaphore VS. Monitors
Semaphore.WaitOne/Release vs Monitor.Pulse/Wait
Monitor.Wait and Monitor.Pulse are fundamental synchronization mechanisms that can be used to form pretty much any other synchronization device including semaphores.
结论,使用Monitor能够达到多线程的目的,lock可以简化这个过程。
4)Terminating a thread cleanly
5) Should a return statement be inside or outside a lock?
At the IL level they are identical。
Only the current owner of the lock can signal a waiting object using Pulse.
The Pulse, PulseAll, and Wait methods must be invoked from within a synchronized block of code.
一个下载线程的例子:
private class DownloadFactory {
#region ===== 线程共享资源 =====
private volatile bool isOpen;
private Queue workingJobs = new Queue();
private Queue finishedJobs = new Queue();
#endregion
const int WORK_NUM = 5; // 开启5个下载线程
private Thread[] workers; // 工作线程,负责下载
private Thread checker; // 检测线程, 用来写磁盘或则重新下载
public DownloadFactory() {
isOpen = false;
workers = new Thread[WORK_NUM];
for (int i = 0; i < WORK_NUM; i++) {
workers[i] = new Thread(() => {
while (isOpen) {
var job = takeJob();
// do download affairs!
finJob(job);
}
});
}
checker = new Thread(() => {
while (isOpen) {
var job = checkJob();
if (!job.isOK) { // 下载不成功,则重新下载
putJob(job);
} else { // 写文件操作
}
}
});
}
public bool isDone {
get {
return totalCount == 0;
}
}
// 开始
public void Open(Queue _allJobs) {
workingJobs = _allJobs;
isOpen = true;
checker.Start();
foreach (var w in workers) {
w.Start();
}
}
// 结束
public void Close() {
isOpen = false;
checker.Interrupt();
foreach (var w in workers) {
w.Interrupt();
}
checker.Join();
foreach (var w in workers) {
w.Join();
}
}
#region ========= 线程同步逻辑 ===========
private int totalCount {
get {
lock (this) {
return workingJobs.Count + finishedJobs.Count;
}
}
}
private DownloadJob takeJob() {
lock (this) {
while (workingJobs.Count <= 0) {
Monitor.Wait(this);
}
var rt = workingJobs.Dequeue();
Monitor.PulseAll(this);
return rt;
}
}
private void putJob(DownloadJob job) {
lock (this) {
workingJobs.Enqueue(job);
Monitor.PulseAll(this);
}
}
private void finJob(DownloadJob job) {
lock (this) {
finishedJobs.Enqueue(job);
Monitor.PulseAll(this);
}
}
private DownloadJob checkJob() {
lock(this) {
while (finishedJobs.Count <= 0) {
Monitor.Wait(this);
}
var job = finishedJobs.Dequeue();
Monitor.PulseAll(this);
return job;
}
}
#endregion
}
例子:生产消费者模式
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEngine.UI;
public class MultiThread : MonoBehaviour {
private List threads = new List();
public Text txtMessage;
public Text txtMsg2;
void Start() {
var kitchen = new Kitchen();
var table = new Table(10);
var msgHandler = new TMsgHandler(this, msg => {
txtMsg2.text = msg as string;
});
ThreadHelper.Run eater = env => {
try {
var random = new System.Random((int)env.param);
while (env.alive) {
var cake = table.take();
Thread.Sleep(random.Next(100));
msgHandler.send(delegate {
txtMessage.text = env.name + "" + cake;
});
}
} catch (ThreadInterruptedException ex) {
msgHandler.send(delegate {
txtMessage.text = string.Format("The {0} Interrupted!", env.name);
});
} finally {
msgHandler.send(delegate {
txtMessage.text = string.Format("The {0} Ended!", env.name);
});
}
};
ThreadHelper.Run maker = env => {
try {
var param = env.param as object[];
var random = new System.Random((int)param[1]);
while (env.alive) {
Thread.Sleep(random.Next(100));
var cake = string.Format("[ Cake No.{0} by {1} ]", kitchen.nextCakeId, env.name);
table.put(cake);
msgHandler.send(env.name + "" + cake);
}
} catch (ThreadInterruptedException ex) {
msgHandler.send(delegate {
txtMessage.text = string.Format("The {0} Interrupted!", env.name);
});
} finally {
msgHandler.send(delegate {
txtMessage.text = string.Format("The {0} Ended!", env.name);
});
}
};
// 一些随机数种子:13821, 97535, 79593, 87481, 66158, 18199, 40915, 63093, 77880, 93602, 17603, 38327
threads.Add(new ThreadHelper("MakerThread-1", maker, new object[] { "111", 13821 }));
threads.Add(new ThreadHelper("MakerThread-2", maker, new object[] { "222", 97535 }));
threads.Add(new ThreadHelper("MakerThread-3", maker, new object[] { "111", 79593 }));
threads.Add(new ThreadHelper("MakerThread-4", maker, new object[] { "222", 87481 }));
threads.Add(new ThreadHelper("MakerThread-5", maker, new object[] { "111", 66158 }));
threads.Add(new ThreadHelper("MakerThread-6", maker, new object[] { "222", 18199 }));
threads.Add(new ThreadHelper("EaterThread-A", eater, 40915));
threads.Add(new ThreadHelper("EaterThread-B", eater, 63093));
threads.Add(new ThreadHelper("EaterThread-C", eater, 77880));
threads.Add(new ThreadHelper("EaterThread-D", eater, 93602));
threads.Add(new ThreadHelper("EaterThread-E", eater, 17603));
threads.Add(new ThreadHelper("EaterThread-F", eater, 38327));
// 开始线程
threads.ForEach(t => t.Start());
}
void OnDestroy() {
threads.ForEach(m => m.Kill());
}
// 同步消息到主线程,模拟android.os.Handler的概念
public class TMsgHandler {
public delegate void PostHandler();
private System.Action
更加有趣的一个版本:
using UnityEngine;
using System.Collections;
using System.Threading;
using System.Collections.Generic;
// 一个线程辅助类
public class ThreadObj {
protected System.Action run = null;
public volatile bool alive;
public string thdName { get { return thread.Name; } }
public Thread thread { get; private set; }
public object param = null;
public ThreadObj(string name, System.Action _run = null, object _param = null) {
alive = false;
run = _run;
param = _param;
thread = new Thread(_inner_run);
thread.Name = name;
//background threads do not prevent a process from terminating.
//Once all foreground threads belonging to a process have terminated,
//the common language runtime ends the process.
thread.IsBackground = true;
}
public void _inner_run() {
if (run != null) {
run(this);
}
}
public void Start() {
alive = true;
thread.Start();
}
public void notifyStop() {
alive = false;
}
public void Kill(int timeout = 0) {
thread.Interrupt();
thread.Join(timeout);
}
}
// 同步消息到主线程,模拟android.os.Handler的概念
public class TMsgHandler {
public delegate void PostHandler();
private System.Action msgHandler;
private List messages = new List();
public TMsgHandler(MonoBehaviour mono, System.Action handler = null) {
msgHandler = handler;
mono.StartCoroutine(checkMessage());
}
public void send(object param) {
lock (this) {
messages.Add(param);
}
}
private List getMessages() {
lock (this) {
if (messages.Count > 0) {
var old = messages;
messages = new List();
return old;
}
return null;
}
}
private IEnumerator checkMessage() {
while (true) {
yield return null;
var msgs = getMessages();
if (msgs != null) {
foreach (var m in msgs) {
if (m is PostHandler) {
var h = m as PostHandler;
h();
} else {
if (msgHandler != null) {
msgHandler(m);
}
}
}
}
}
}
}
using UnityEngine;
using UnityEngine.UI;
// 餐厅表现
public class UIDiningHall : MonoBehaviour {
public Text cakeNo;
public Table table;
public Transform makers;
public Transform eaters;
private DiningHall diningHall = new DiningHall();
// Use this for initialization
void Start () {
var msgHandler = new TMsgHandler(this, msg => {
if (msg is Maker.Event) { // 厨师消息
Debug.Log(msg.ToString());
} else if (msg is Eater.Event) { // 食客消息
Debug.Log(msg.ToString());
}
});
diningHall.Init(msgHandler);
diningHall.Open(); // 餐厅营业
}
void OnDestroy() {
Debug.LogError("=========Dining Hall is Closing===========");
diningHall.Close(); // 餐厅打烊
}
}
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
// 餐厅, 逻辑运行
public class DiningHall {
private List persons = new List(); // 餐厅中的人,包括厨师和食客
public Kitchen kitchen { get; private set; }
public Table table { get; private set; }
private TMsgHandler handler;
public void Init(TMsgHandler msgHandler) {
handler = msgHandler;
kitchen = new Kitchen(30);
table = new Table(5);
// 一些随机数种子:13821, 97535, 79593, 87481, 66158, 18199,
// 40915, 63093, 77880, 93602, 17603, 38327
// 创建一些厨师
persons.Add(new Maker("CookA", 1, 13821, this));
persons.Add(new Maker("CookB", 1, 97535, this));
persons.Add(new Maker("CookC", 1, 79593, this));
persons.Add(new Maker("CookD", 1, 87481, this));
persons.Add(new Maker("CookE", 1, 87481, this));
persons.Add(new Maker("CookF", 1, 87481, this));
persons.Add(new Maker("CookG", 1, 87481, this));
persons.Add(new Maker("CookA", 1, 13821, this));
// 创建一些食客
persons.Add(new Eater("Eater1", 10, 40915, this));
persons.Add(new Eater("Eater2", 20, 63093, this));
persons.Add(new Eater("Eater3", 30, 77880, this));
persons.Add(new Eater("Eater4", 40, 93602, this));
persons.Add(new Eater("Eater1", 10, 40915, this));
persons.Add(new Eater("Eater2", 20, 63093, this));
persons.Add(new Eater("Eater3", 30, 77880, this));
persons.Add(new Eater("Eater4", 40, 93602, this));;
}
// 发送信息到UI
public void send2UI(object param) {
handler.send(param);
}
public Cake takeCake() {
return table.take();
}
// 开始营业
public void Open() {
// 开始线程, 让餐厅运作起来
persons.ForEach(t => t.Start());
}
// 结束营业
public void Close() {
persons.ForEach(t => t.Kill());
}
}
class Eater : ThreadObj {
public string name { get; private set; } // 食客的名字
public int speed { get; private set; } // 食客吃蛋糕的速度
private System.Random rand;
private DiningHall dh;
public Eater(string name, int speed, int seed, DiningHall dh) : base(name) {
this.name = name;
this.speed = speed;
this.rand = new System.Random(seed);
this.dh = dh;
this.run = Run;
}
// 食客在餐厅中取餐并吃~~
private void Run(ThreadObj env) {
try {
while (env.alive) {
// 获取蛋糕
Event.takeStart(this);
var cake = dh.takeCake();
// 开始吃蛋糕, 直至吃完
while (cake.percent > 0) {
cake.eat(rand.Next(speed)); // 计算一口的大小
Event.eatStart(this, cake);
Thread.Sleep(100); // 每吃一口,要咀嚼一下
}
Debug.LogWarning("[Eater] " + cake.ToString());
// 蛋糕吃完了
Event.eatEnd(this);
}
} catch (ThreadInterruptedException ex) {
} finally {
}
}
// 食客消息, 和UI通信的消息
public class Event {
public int id { get; private set; }
public int type { get; private set; }
public Cake cake { get; private set; }
public static void takeStart(Eater eater) {
eater.dh.send2UI(new Event() { type = 0 });
}
public static void eatStart(Eater eater, Cake _cake) {
eater.dh.send2UI(new Event() { type = 1, cake = _cake.clone() });
}
public static void eatEnd(Eater eater) {
eater.dh.send2UI(new Event() { type = 2 });
}
public override string ToString() {
return string.Format("[Eater] type: {0}, cake: {1}", type, cake == null ? "-" : cake.ToString());
}
}
}
// 厨师
public class Maker : ThreadObj {
public string name { get; private set; } // 厨师的名字
public float speed { get; private set; } // 厨师制作蛋糕的速度
private System.Random rand;
private DiningHall dh;
public Maker(string name, float speed, int seed, DiningHall dh) : base(name) {
this.name = name;
this.speed = speed;
this.rand = new System.Random(seed);
this.dh = dh;
this.run = Run;
}
// 厨师工作中~~
private void Run(ThreadObj env) {
try {
while (env.alive) {
// 0. 获取蛋糕机的使用
Event.waitMachine(this);
var machine = dh.kitchen.getMachine(); // 获取蛋糕机
// 1. 设计一个蛋糕,并让面包机做
//dh.send2UI(Event.makeStart(cake)); // 开始制作
var type = rand.Next(5);
var amount = rand.Next(50, 200);
var cake = new Cake(type, amount);
machine.Cook(cake); // 制作蛋糕中~~
Event.waitCooking(this, cake);
cake = machine.GetCake(); //得到蛋糕
// 2. 放置蛋糕
Event.putCake(this);
dh.table.put(cake);
Event.putCakeEnd(this);
}
} catch (ThreadInterruptedException ex) {
} finally {
}
}
public class Event {
public int type { get; private set; }
public Cake cake { get; private set; }
public static void waitMachine(Maker m) {
m.dh.send2UI(new Event() { type = 0 });
}
public static void waitCooking(Maker m, Cake c) { // 等待
m.dh.send2UI(new Event() { type = 1, cake = c.clone() });
}
public static void putCake(Maker m) {
m.dh.send2UI(new Event() { type = 2 });
}
public static void putCakeEnd(Maker m) {
m.dh.send2UI(new Event() { type = 3 });
}
public override string ToString() {
return string.Format("[Maker] type: {0}, cake: {1}", type, cake==null ? "-" : cake.ToString());
}
}
}
// 蛋糕
public class Cake {
static int ID = 0;
private int _id = 0;
public int type { get; private set; } // 蛋糕类型
public float totalAmount { get; private set; } // 蛋糕的设计尺寸
public float curAmount { get; private set; } // 当前蛋糕的尺寸
private int status; // 0 表示制作中, 1表示制作完成; -1 表示状态不可变(由于UI显示)
public float percent { get { return curAmount / (float)totalAmount; } }
public Cake(int type, float totalAmount, int id=-1, float curAmount =0, int status = 0) {
this.type = type;
this.totalAmount = totalAmount;
this.curAmount = curAmount;
this.status = status;
_id = id < 0 ? ++ID : id;
}
public int id {
get {
return _id;
}
}
// 制作蛋糕
public void make(float amount) {
if (status == 0) {
curAmount += amount;
if (curAmount >= totalAmount) {
curAmount = totalAmount;
status = 1;
}
}
}
// 吃蛋糕
public void eat(int amount) {
if (status == 1) {
curAmount -= amount;
if (curAmount <= 0) {
curAmount = 0;
status = -1;
}
}
}
public Cake clone() {
return new Cake(type, totalAmount, id, curAmount, status) ;
}
public override string ToString() {
return string.Format("{{ id: {0}, type: {1}, total: {2:0.0}, cur: {3:0.0}, status: {4}, percent: {5:0.0} }}",
id, type, totalAmount, curAmount, status, percent);
}
}
// 蛋糕机
public class CakeMachine {
public Kitchen kitchen { get; private set; }
private Cake curCake = null;
private bool isCooking = false;
public CakeMachine(string name, Kitchen kitchen) {
this.kitchen = kitchen;
}
private void Run() {
if (curCake != null) {
while (curCake.percent < 1) {
curCake.make(10);
Thread.Sleep(100); // 制作时间
}
Debug.LogError("Done!" + curCake.id );
MarkAsDone();
}
}
// 开始做蛋糕
public void Cook(Cake cake) {
lock (this) {
while (isCooking) {
Monitor.Wait(this);
}
curCake = cake;
isCooking = true;
Debug.LogWarning("[Cook] " + curCake.ToString());
var thread = new Thread(Run);
thread.IsBackground = true;
thread.Start();
}
}
// 拿出蛋糕
public Cake GetCake() {
lock(this) {
while (isCooking) {
Monitor.Wait(this);
}
return curCake.clone();
}
}
// 手动结束
public void ShutDown() {
lock (this) {
//Kill();
MarkAsDone();
}
}
// 蛋糕做好了
public void MarkAsDone() {
lock (this) {
isCooking = false;
Monitor.PulseAll(this);
kitchen.MachineReady();
}
}
public bool isDone {
get {
lock (this) {
return !isCooking;
}
}
}
}
// 厨房, 里面有蛋糕机
public class Kitchen {
private List machines; // 蛋糕机
public Kitchen(int machineNum) {
machines = new List();
for (int i = 0; i < machineNum; i++) {
machines.Add(new CakeMachine("M" + i, this));
}
}
public CakeMachine getMachine() { // 尝试获取一台可用的机器
lock (this) {
CakeMachine free = null;
while (free == null) {
free = machines.Find(m => m.isDone);
if (free == null) { // 没有机器是空闲的,需要等待
Monitor.Wait(this);
}
}
return free;
}
}
public void MachineReady() { // 某台机器用好了
lock (this) {
Monitor.PulseAll(this);
}
}
}
// 定义桌子,注意这个是共享资源!!厨师和食客共享
public class Table {
private Cake[] buffer;
private int tail;
private int head;
private int count;
public Table(int _count) {
this.buffer = new Cake[_count];
tail = head = count = 0;
}
public void put(Cake cake) {
lock (this) {
while (count >= buffer.Length) {
Monitor.Wait(this);
}
buffer[tail] = cake;
tail = (tail + 1) % buffer.Length;
count++;
Monitor.Pulse(this);
}
}
public Cake take() {
lock (this) {
while (count <= 0) {
Monitor.Wait(this);
}
var cake = buffer[head];
head = (head + 1) % buffer.Length;
count--;
Monitor.Pulse(this);
return cake;
}
}
}
由于自己项目中使用XML作为配置文件,为了解析起来方便,其实更加方便的是解析XML的.cs文件都通过程序去生成,读者可以自己去实现,下面是XML解析器,仅供大家参考!先来看看最终使用例子的代码(在我们的项目中,我们需要借助上一篇的资源加载管理器来预先加载我们的配置文件):using UnityEngine;using System.Collections;public class LoaderXm
1. aggregateByKey的运行机制
/**
* Aggregate the values of each key, using given combine functions and a neutral "zero value".
* This function can return a different result type
spark-sql是Spark bin目录下的一个可执行脚本,它的目的是通过这个脚本执行Hive的命令,即原来通过
hive>输入的指令可以通过spark-sql>输入的指令来完成。
spark-sql可以使用内置的Hive metadata-store,也可以使用已经独立安装的Hive的metadata store
关于Hive build into Spark
// Max value in Array
var arr = [1,2,3,5,3,2];Math.max.apply(null, arr); // 5
// Max value in Jaon Array
var arr = [{"x":"8/11/2009","y":0.026572007},{"x"
在使用XMlhttpRequest对象发送请求和响应之前,必须首先使用javaScript对象创建一个XMLHttpRquest对象。
var xmlhttp;
function getXMLHttpRequest(){
if(window.ActiveXObject){
xmlhttp:new ActiveXObject("Microsoft.XMLHTTP