using System; using System.Diagnostics; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Threading; using System.Linq; #pragma warning disable 0420 public partial class LockFreeDictionary<K, V> : IDictionary<K, V> where K : IEquatable<K> where V : IEquatable<V> { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public partial class EntryBlock { public EntryBlock(Config cfg, int block_no) { this.cfg = cfg; this.i_block = block_no; this.rg = new Entry[cfg.EntriesPerBlock]; } readonly Config cfg; readonly int i_block; readonly Entry[] rg; volatile public EntryBlock next = null; internal int BlockIndex { get { return i_block; } } internal void GetEntryLoose(int offs, out Entry e) { e = rg[offs]; Thread.MemoryBarrier(); } internal void StoreEntryLoose(int offs, ref Entry e) { Thread.MemoryBarrier(); rg[offs] = e; } internal void SetEntryNext(int offs, int gx_next) { rg[offs].gx_next = gx_next; /// C# volatile } internal int GetEntryNext(int offs) { return rg[offs].gx_next; /// C# volatile } internal void GetKeyReadback(int offs, out K key) { if (Entry.f_value_type_key) { //do { key = rg[offs].key; Thread.MemoryBarrier(); } //while (!key.Equals(rg[offs].key)); } else { key = rg[offs].key; Thread.MemoryBarrier(); } } internal uint GetHashAndNext(int offs, out int gx_next) { gx_next = rg[offs].gx_next; /// C# volatile return rg[offs].hash; /// C# volatile } /// <summary> /// Note: still not atomic against torn reads matching as false positives /// </summary> internal void SetEntryValueReadback(int offs, ref V value) { if (Entry.f_value_type_value) { //do { Thread.MemoryBarrier(); rg[offs].value = value; //Thread.MemoryBarrier(); /// read fence for external code 'Equals' } //while (!value.Equals(rg[offs].value)); } else { Thread.MemoryBarrier(); rg[offs].value = value; } } internal void SetEntryValueLoose(int offs, ref V value) { Thread.MemoryBarrier(); rg[offs].value = value; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public partial struct Entry { static readonly int cb_ent; static internal int StructureSize { get { return cb_ent; } } static internal Type t_key; static internal Type t_value; static internal readonly bool f_value_type_key; static internal readonly bool f_value_type_value; static Entry() { t_key = typeof(K); t_value = typeof(V); f_value_type_key = t_key.IsValueType; f_value_type_value = t_value.IsValueType; cb_ent = sizeof(int) + sizeof(uint); cb_ent += f_value_type_key ? Marshal.SizeOf(default(K)) : IntPtr.Size; cb_ent += f_value_type_value ? Marshal.SizeOf(default(V)) : IntPtr.Size; } internal Entry(int gx_next, uint hash, K key, V value) { this.gx_next = gx_next; this.hash = hash; this.key = key; this.value = value; } volatile internal int gx_next; volatile internal uint hash; readonly internal K key; internal V value; }; }; };