c# - Thread synchonization -
i have list of commands processed concurrently on multiple threads. list static, each thread generates output , not interfere other threads, works ok far.
some of commands require complex calculations on dataset accompanies command. result of calculations same threads. @ moment each thread performs calculations when reaches command waste of time , resources.
what perform calculation once , share results between threads. thread reaches first command starts calculation, other threads reach command wait till calculation complete , use result.
i have little experience thread synchronization , not know synchronization primitives should use scenario , should put lock on calculation. can tell me classes (for synchronization) should use in scenario , thread should wait , on object?
my code looks this:
private void threadfunc(object state) { context ctx = (context)state; command cmd = ctx.commandlist; processor proc = ctx.processor; while (cmd != null) { switch(cmd.type) { case commandtype.simple: proc.executesimplecommand(cmd); break; case commandtype.complex: cmd.data = computedata(cmd.dataset); proc.executecomplexcommand(cmd); break; } cmd = cmd.next; } }
the computedata method performs complex calculation , result stored on command.
code has problem @ moment because each thread sets data property on same command object since calculation result same threads code works.
i thinking of i'm not sure if correct:
case commandtype.complex: lock (cmd) { if (cmd.data == null) { cmd.data = computedata(cmd.dataset); } } proc.executecomplexcommand(cmd); break;
edit: i'm limited on .net 2.0 @ moment.
edit 2: list fixed, elements not change. threads read list, not modify list.
i'll try example: list contains elements a, b , c , processed threads t1 , t2. when t1 reaches b, calls computedata method , stores result in property of b. when t2 reaches b waits till calculation on (assuming t1 reached b before , called computedata) , uses result. want achieve.
basically you're attempting grab head of linked list , move next location. 'grab' issue here; it's easy put loop around it.
with locks
the easy solution use lock:
private static object lockobject = new object(); // ... command current; lock (lockobject) { current = commandlist; commandlist = commandlist.next; } // use current.
alternatively, can use spinlock.
without locks
while it's tricky make thread-safe code without locks, here's attempt (warning: there might bugs in here; haven't thoroughly checked code!):
thread.memorybarrier(); // read barrier var list = commandlist; if (list != null) { var next = list.next; if (interlocked.compareexchange(ref commandlist, next, list) == list) { // execute code on 'list'. } else { // changed. try again. } }
let's change question...
sometimes dialogue makes things more confusing...
the thread reaches first command starts calculation, other threads reach command wait till calculation complete , use result.
and
simple commands can run in parallel without problems. complex commands can run in parallel (this i'm doing now) same calculation performed on each thread , waste of time.
so let's straight: let's assume have chain a->b->c , c simple commands , b complex command. want a,b run in parallel , want run c after b has finished. while executing b should wait until done.
one simple solution comes mind: let's assume simple commands have no data , complex commands have data. you've said list created before invoking all. means don't have lot of synchronization.
basically can follows:
var current = this.commandlist; while (current != null) { if (current.data != null) // complex command? (b) { lock (current.data) // threads wait here except 1 { if (current.executed) // execute once. { // go ahead , execute it, single threaded // [code] current.executed = true; } } } else { bool executehere = false; // simple command. lock (lockobject) // shared lock object { executehere = !command.executed; // execute in thread? command.executed = true; } // true in 1 thread only, multiple a's/c's can executed in parallel. if (executehere) { // execute simple command // [code] } } current = current.next; }
Comments
Post a Comment