c# - Exception when attempting to modify Dictionary -
i creating dictionary manage threads , ran exception when attempt clear dead threads after adding threads dictionary.
using system; using system.collections.generic; using system.threading; namespace syscat { public class threadmanager { public static readonly threadmanager globalthreadmanager = new threadmanager( ); /// <summary> /// initializes new instance of <see cref="syscat.threadmanager"/> class. /// </summary> public threadmanager( ) { } /// <summary> /// create new threadmanager threads within basetm , deinitializes basetm /// </summary> public threadmanager( threadmanager basetm ) { this.threads = basetm.threads; basetm.threads.clear( ); } private dictionary<guid,thread> threads = new dictionary<guid, thread>( ); /// <summary> /// attempts obtain unused threadid within attempt limit /// </summary> /// <returns>the unused threadid, if found</returns> /// <param name="attempts">the number of iterations try.</param> public guid getunusedthreadid( int attempts ) { lock( threads ) { guid threadid; int totalattempts = attempts; while( threads.containskey( ( threadid = guid.newguid( ) ) ) ) { attempts--; if( attempts == 0 ) throw new noopenthreadidexception( totalattempts ); } return threadid; } } /// <summary> /// attempts thread via threadid, if exists /// </summary> /// <returns>the thread</returns> /// <param name="threadid">the threadid use</param> public thread getthread( guid threadid ) { lock( threads ) { thread tryget; if( !threads.trygetvalue( threadid, out tryget ) ) throw new argumentexception( "specified threadid not exist in threadmanager" ); return tryget; } } /// <summary> /// attempts threadid via thread /// </summary> /// <returns>the threadid</returns> /// <param name="thread">the thread use</param> public guid getthreadid( thread thread ) { lock( threads ) { if( threads.containsvalue( thread ) ) { foreach( guid id in threads.keys ) { thread t; threads.trygetvalue( id, out t ); if( t.equals( thread ) ) return id; } // should never here return guid.empty; } else throw new argumentexception( "specified thread not exist in threadmanager" ); } } /// <summary> /// adds thread, unless cannot find open threadid /// </summary> /// <returns>the threadid used register thread</returns> /// <param name="thread">the thread register</param> public guid addthread( thread thread ) { lock( threads ) { guid id; try { id = getunusedthreadid( 500 ); } catch( noopenthreadidexception e ) { throw e; } threads.add( id, thread ); return id; } } /// <summary> /// attempts clear stopped , null threads /// </summary> /// <returns>the number of dead threads cleared</returns> public int cleardeadthreads() { int cleared = 0; lock(threads) { foreach( guid id in threads.keys ) { thread thread; threads.trygetvalue( id, out thread ); if( thread == null ) { // not exist, thread dead cleared++; threads.remove( id ); continue; } if( !thread.isalive ) { // not alive, thread dead cleared++; threads.remove( id ); continue; } } } return cleared; } public class noopenthreadidexception : exception { public noopenthreadidexception( int attempts ) : base( string.format( "unable find open threadid within attempt limit of {0}", attempts ) ) { } } } }
and getting exception: system.invalidoperationexception message: collection modified; enumeration operation may not execute
i unsure why happening, appreciated.
this code used test it:
using system; using system.collections; using system.io; using system.collections.generic; using system.threading; using _tm = syscat.threadmanager; namespace syscat { public class syscat { thread t = new thread( new threadstart( delegate { while(true) thread.sleep(250); } ) ); thread t2 = new thread( new threadstart( delegate { } ) ); thread t3 = new thread( new threadstart( delegate { } ) ); _tm.globalthreadmanager.addthread( t ); _tm.globalthreadmanager.addthread( t2 ); _tm.globalthreadmanager.addthread( t3 ); console.writeline( _tm.globalthreadmanager.cleardeadthreads( ) ); console.readline( ); } } }
you can not modify ienumerable
while enumerating on it.
you can simple hack , copy of enumerating changes in not result in system.invalidoperationexception
.
for example instead of
foreach( guid id in threads.keys)
use
foreach( guid id in threads.keys.tolist())
keep in mind can use data structures supports concurrency
Comments
Post a Comment