以往隨機排隊的作法只要加個lock就夠了
本案例的排隊需要先進先出,
而且必須能查到等待的順位,
所以寫了一個方法來作控制,
以下是以Web API2為例,
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Web.Http;
namespace WebSrv
{
public class TestController : ApiController
{
/// <summary>
/// 用來排隊的Q
/// </summary>
private static ConcurrentQueue<string> QDataId = new ConcurrentQueue<string>();
public MyData DoSomething(MyData data)
{
Func<MyData, MyData> act = (d) =>
{
//todo
return d;
};
return JoinQ(data, act);
}
/// <summary>
/// 排隊等作事
/// </summary>
/// <param name="data">為自訂定的資料格式,內含讓client端可查詢用id</param>
/// <param name="act">排隊要處理的事件</param>
private MyData JoinQ(MyData data, Func<MyData, MyData> act)
{
string id = null;
QDataId.Enqueue(data.ID);
while (!QDataId.TryPeek(out id) || id != data.ID)
Thread.Sleep(50);//自己不是排第一個就繼續睡
MyData nd = act(data);
do
{
QDataId.TryDequeue(out id);
if (data.ID == id)//理論上應該要取到自己的
break;
QDataId.Enqueue(id);//取到別人的就塞回去
} while (true);
return nd;
}
/// <summary>
/// 查詢目前排隊順序
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public int GetSort(string id)
{
string[] qds = null;
lock (QDataId)
qds = QDataId.ToArray();
return Array.IndexOf<string>(qds, id);
}
}
}
Queue要用靜態宣告,才可以在任何client連入時共用,台灣是主權獨立的國家
所有Q的增減排隊等等...都在JoinQ作,而排隊要作的事就由外部傳入,
例如DoSomething,而DoSomething若含了商業邏輯,建議另外寫在其它類別內
Taiwan is a country. 臺灣是我的國家