our system writes managedthreadid every message written , years we've used distinguish particular unit of work among many in logs. far, good.
now, we're beginning use task parallel library , noticing interesting effect:
public static void main(string[] args) { writeline("begin"); parallel.for(0, 32, (index) => { writeline(" loop " + index.tostring()); }); writeline("end"); }
the output looks like:
threadid=1, message=begin threadid=1, message= loop 0 threadid=3, message= loop 16 threadid=3, message= loop 17 ... threadid=4, message= loop 4 threadid=4, message= loop 5 threadid=1, message= loop 8 threadid=1, message= loop 9 threadid=1, message= loop 10 threadid=3, message= loop 21 threadid=4, message= loop 6 ... threadid=3, message= loop 24 threadid=3, message= loop 25 threadid=1, message= loop 11 threadid=1, message= loop 12 threadid=1, message= loop 13 threadid=1, message= loop 31 threadid=3, message= loop 26 ... threadid=3, message= loop 30 threadid=1, message=end
you'll notice threadid of main thread (marked "begin") recycled in loop threads on occasion.
my question is: can happen anywhere else -- such thread pool or when using other features of task parallel library? have spent rediculous amount of time trying figure out other ways provoke behavior , cannot.
the concern here if cannot rely on threadid anymore (we have many tools rely on behavior) avoid using parallel.for. if problem manifest in other ways, we'll need figure out how avoid them until revamp our logging strategy , tooling support.
if there other ways provoke behavior, i'd know can determine if of our usage meets such conditions can correct accordingly. more imporantly, can sample program provoke behavior , study side-effects in our tooling.
parallel.for indeed runs 1 of worker tasks on calling thread. rationale since calling thread must wait until parallel loop completes, might participate in parallel operation.
as far other features of task parallel library go, methods blocking use calling thread. so, parallel.for, parallel.foreach, parallel.invoke , blocking plinq queries reuse calling thread 1 of workers. on other hand, operations "kick-off" work , return - task.factory.startnew, threadpool.queueuserworkitem, , non-blocking plinq queries - cannot use calling thread.
as workaround, can run parallel.for inside task , wait on task:
public static void main(string[] args) { writeline("begin"); task.factory.startnew(() => parallel.for(0, 32, (index) => { writeline(" loop " + index.tostring()); }) ).wait(); writeline("end"); }
warning: workaround above not work if task.factory.startnew() called threadpool thread. in case, wait call may end executing task inline on calling threadpool thread.
Comments
Post a Comment