我想要實現下列數據類型在C#實現併發安全的自定義數據類型的
public class MyType
{
void Set(int i);
void AddHandler(int i, Action action);
}
語義如下。
- 兩種方法都必須是安全的併發。
- 'i'的最大值已知,相對較低(〜100)。
- 試圖設置我不止一次應該失敗。
- 具有價值的調用集我應該調用所有處理程序註冊該我。
- AddHandler爲給定的i註冊新的處理程序。如果我已經設置好,立即調用行動。
例如,考慮以下序列
Set(1)
Set(2)
AddHandler(3, f1)
AddHandler(3, f2)
Set(1) // Fails, 1 is already set
AddHandler(2, g) // g is called as 2 is already set
Set(3) // f1, f2 are called
AddHandler(3, h) // h is called as 3 is now set
目標是最小化所需要的每個方法調用來完成分配。這是我嘗試實現它的代碼。
public class MyType
{
const int N = 10;
static readonly Action[] s_emptyHandler = new Action[0];
readonly bool[] m_vars = new bool[N];
readonly List<Action>[] m_handlers = new List<Action>[N];
public void Set(int i)
{
Action[] handlers;
lock (this)
{
if (m_vars[i]) throw new InvalidOperationException();
m_vars[i] = true;
handlers = m_handlers[i] != null ? m_handlers[i].ToArray() : s_emptyHandler;
}
foreach (var action in handlers)
action();
}
public void AddHandler(int i, Action action)
{
var done = false;
lock (this)
{
if (m_vars[i])
done = true;
else
{
if(m_handlers[i] == null)
m_handlers[i] = new List<Action>();
m_handlers[i].Add(action);
}
}
if (done)
action();
}
}
告訴我們你的代碼,你試圖去做 – Backs
應爲'鎖(myDictionary)一樣簡單{...}' - 只記得不調用鎖內的動作 - 取而代之的是當前的觀察者並在之後調用它們 - 如果你想使用併發收集的東西 – Carsten
謝謝。我編輯了這個問題。關於第二條評論,是的,我有類似的想法。但是這需要我快照當前的一組處理程序。是否有任何併發的收集可以幫助您避免它? – Suyog