using system; using system.collections; using system.collections.generic; using system.diagnostics; using system.io; using system.linq; using system.runtime.serialization; using system.text; using system.threading; using system.threading.tasks; namespace threadsafeenumerable { public static class counter { public static long alive = 0; public static long dead = 0; } public class threadsafeenumerator<t> : ienumerator<t> { private readonly ienumerator<t> _innercollection; private readonly readerwriterlockslim _rwlock; public threadsafeenumerator(ienumerator<t> innercollection, readerwriterlockslim rwlock) { _rwlock = rwlock; _innercollection = innercollection; rwlock.enterreadlock(); ++counter.alive; } public void dispose() { _rwlock.exitreadlock(); --counter.alive; ++counter.dead; } public bool movenext() { return _innercollection.movenext(); } public void reset() { _innercollection.reset(); } public t current { { return _innercollection.current; } } object ienumerator.current { { return current; } } } public class threadsafecollection<t> : ilist<t> { internal list<t> innerlist; readonly readerwriterlockslim _rwlock = new readerwriterlockslim(lockrecursionpolicy.supportsrecursion); protected readerwriterlockslim rwlock { { return _rwlock; } } #region "constructors" protected threadsafecollection() { innerlist = new list<t>(); } protected threadsafecollection(params t[] items) : this() { if (items == null) { return; } addrange(items); } #endregion #region "destructor" ~threadsafecollection() { _rwlock.dispose(); } #endregion #region "public methods" public void addrange(ienumerable<t> items) { try { _rwlock.enterwritelock(); foreach (var item in items.where(x => x != null)) { innerlist.add(item); } } { _rwlock.exitwritelock(); } } #endregion internal void removeall(predicate<t> predicate) { try { _rwlock.enterwritelock(); innerlist.removeall(predicate); } { _rwlock.exitwritelock(); } } #region "interface methods" public ienumerator<t> getenumerator() { _rwlock.enterreadlock(); try { return new threadsafeenumerator<t>(innerlist.getenumerator(), _rwlock); } { _rwlock.exitreadlock(); } } ienumerator ienumerable.getenumerator() { return getenumerator(); } public void add(t item) { try { _rwlock.enterwritelock(); innerlist.add(item); } { _rwlock.exitwritelock(); } } public void clear() { try { _rwlock.enterwritelock(); innerlist.clear(); } { _rwlock.exitwritelock(); } } public bool contains(t item) { try { _rwlock.enterreadlock(); return innerlist.contains(item); } { _rwlock.exitreadlock(); } } public void copyto(t[] array, int arrayindex) { _rwlock.enterreadlock(); innerlist.copyto(array, arrayindex); _rwlock.exitreadlock(); } public bool remove(t item) { try { _rwlock.enterwritelock(); return innerlist.remove(item); } { _rwlock.exitwritelock(); } } public int count { { return innerlist.count; } } public bool isreadonly { { return ((ilist<t>)innerlist).isreadonly; } } public int indexof(t item) { try { _rwlock.enterreadlock(); return innerlist.indexof(item); } { _rwlock.exitreadlock(); } } public void insert(int index, t item) { try { _rwlock.enterwritelock(); innerlist.insert(index, item); } { _rwlock.exitwritelock(); } } public void removeat(int index) { try { _rwlock.enterwritelock(); innerlist.removeat(index); } { _rwlock.exitwritelock(); } } public t this[int index] { { try { _rwlock.enterreadlock(); return innerlist[index]; } { _rwlock.exitreadlock(); } } set { try { _rwlock.enterwritelock(); innerlist[index] = value; } { _rwlock.exitwritelock(); } } } #endregion #region "public override methods" public override bool equals(object obj) { if (obj == null || gettype() != obj.gettype()) { return false; } return == (threadsafecollection<t>)obj; } public override int gethashcode() { try { _rwlock.enterreadlock(); return innerlist.aggregate(17, (current, x) => current + current * 23 + x.gethashcode()); } { _rwlock.exitreadlock(); } } public static bool operator ==(threadsafecollection<t> obj1, threadsafecollection<t> obj2) { if (referenceequals(obj1, obj2)) { return true; } if (referenceequals(obj1, null) || referenceequals(obj2, null)) { return false; } var match = obj1.innerlist.count == obj2.innerlist.count; if (!match) { return false; } (var = 0; < obj1.innerlist.count; i++) { match = obj1.innerlist.any(x => x.equals(obj2.innerlist[i])); if (!match) { break; } } return match; } public static bool operator !=(threadsafecollection<t> obj1, threadsafecollection<t> obj2) { return !(obj1 == obj2); } #endregion #region "protected methods" #endregion } public class mystringcollection : threadsafecollection<string> { } [datacontract] public class mydata { mystringcollection _strings; [datamember] public mystringcollection strings { { if (_strings == null) { _strings = new mystringcollection(); } return _strings; } } } class program { static void main(string[] args) { mydata o1 = new mydata(); o1.strings.add("r1"); o1.strings.add("r2"); o1.strings.add("r3"); console.writeline($"before counter.alive = {counter.alive} "); using (var ms = new memorystream()) { var dcs = new datacontractserializer(o1.gettype()); dcs.writeobject(ms, o1); var serialisedstring = encoding.utf8.getstring(ms.toarray()); } console.writeline($"after counter.alive = {counter.alive} "); try { o1.strings.add("r4"); } catch (exception ex) { console.writeline(ex); } console.writeline("exit."); } } }
i using datacontractserializer
serialize collection. collection implemented thread safe class threadsafecollection
. threadsafecollection
implements ilist<t>
. function ienumerator<t>.getenumerator()
implemented in class. returns threadsafeenumerator
class object. threadsafeenumerator
implemented me.
problem:
dispose function in threadsafeenumerator
not getting called. due read lock of _rwlock (type readerwriterlockslim) not getting released. due not able acquire write lock when add called. see code in main function try catch tries add fails.
Comments
Post a Comment