multithreading - Safe Way to Limit Running Threads C# -


i have program writing run variety of tasks. have set have called "task queue" in continually grab next task process (if there one) , start new thread handle task. however, want limit amount of threads can spawn @ 1 time apparent reasons. created variable keep max threads spawn , 1 current thread count. thinking of using lock try , accurately keep current thread count. here general idea.

public class program {   private static int mintthreadcount;   private static int mintmaxthreadcount = 10;   private static object mobjlock = new object();   static void main(string[] args) {      mintthreadcount = 0;      int = 100;      while(i > 0) {         startnewthread();         i--;      }      console.read();   }    private static void startnewthread() {      lock(mobjlock) {         if(mintthreadcount < mintmaxthreadcount) {            thread newthread = new thread(starttask);            newthread.start(mintthreadcount);            mintthreadcount++;         }         else {            console.writeline("max thread count reached.");         }      }   }    private static void starttask(object icurrentthreadcount) {      int id = new random().next(0, 1000000);      console.writeline("new thread id of: " + id.tostring() + " started. current thread count: " + ((int)icurrentthreadcount).tostring());      thread.sleep(new random().next(0, 3000));      lock(mobjlock) {         console.writeline("ending thread id of: " + id.tostring() + " now.");         mintthreadcount--;         console.writeline("thread space release id of: " + id.tostring() + " . thread count at: " + mintthreadcount);      }   } } 

since locking in 2 places access same variable (increment when starting new thread , decrement when ending it) there chance thread waiting on lock decrement hung , never end? thereby reaching max thread count , never being able start one? alternate suggestions method?

easiest question first… :)

…is there chance thread waiting on lock decrement hung , never end?

no, not in code posted. none of code holds lock while waiting count change, or that. ever take lock, either modify count or emit message, , release lock. no thread hold lock indefinitely, nor there nested locks (which lead deadlock if done incorrectly).

now, said: code posted , question, it's not entirely clear intent here is. code written indeed limit number of threads created. once limit reached (and quickly), main loop spin, reporting "max thread count reached.".

indeed, total loop count of 100, think it's possible entire loop finish before first thread gets run, depending on else tying cpu cores on system. if threads run , happens of them low durations sleep, there's chance might sneak in few more threads later. of iterations of loop see thread count @ maximum, report limit has been reached , continue next iteration of loop.

you write in comments (something should put in question itself, if think it's relevant) "the main thread should never blocked". of course, question there is, main thread doing when not blocked? how main thread know if , when try schedule new thread?

these important details, if want useful answer.

note you've been offered suggestion of using semaphore (specifically, semaphoreslim). could idea, note that class typically used coordinate multiple threads competing same resource. useful, you'd have more 10 threads, semaphore ensuring 10 run @ given time.

in case, seems me asking how avoid creating thread in first place. i.e. want main loop check count , not create thread @ if maximum count reached. in case, 1 possible solution might use monitor class directly:

private static void startnewthread() {     lock(mobjlock) {         while (mintthreadcount >= mintmaxthreadcount) {            console.writeline("max thread count reached.");            monitor.wait(mobjlock);         }          thread newthread = new thread(starttask);         newthread.start(mintthreadcount);         mintthreadcount++;         }     } } 

the above cause startnewthread() method wait until count below maximum, , create new thread.

of course, each thread needs signal it's updated count, above loop can released wait , check count:

private readonly random _rnd = new random();  private static void starttask(object icurrentthreadcount) {     int id = _rnd.next(0, 1000000);     console.writeline("new thread id of: " + id.tostring() + " started. current thread count: " + ((int)icurrentthreadcount).tostring());     thread.sleep(_rnd.next(0, 3000));     lock(mobjlock) {         console.writeline("ending thread id of: " + id.tostring() + " now.");         mintthreadcount--;         console.writeline("thread space release id of: " + id.tostring() + " . thread count at: " + mintthreadcount);         monitor.pulse(mobjlock);     } } 

the problem above will block main loop. if understood correctly, don't want.

(note: have common-but-serious bug in code, in create new random object each time want random number. use random class correctly, must create 1 instance , reuse want new random numbers. i've adjusted code example above fix problem).

one of other problems, both above, , original version, each new task assigned brand new thread. threads expensive create , exist, why thread pools exist. depending on actual scenario is, it's possible should using e.g. parallel, parallelenumerable, or task manage tasks.

but if want explicitly, 1 option start ten threads, , have them retrieve data operate on blockingcollection<t>. since start ten threads, know you'll never have more running. when there enough work ten threads busy, be. otherwise, queue empty , or waiting new data show in queue. idle, not using cpu resources.

for example:

private blockingcollection<int> _queue = new blockingcollection<int>();  private static void startthreads() {     (int = 0; < mintmaxthreadcount; i++) {         new thread(starttask).start();     } }  private static void starttask() {     // note: random number can't reliable "identification", 2 or     // more threads theoretically same "id".     int id = new random().next(0, 1000000);     console.writeline("new thread id of: " + id.tostring() + " started.");     foreach (int in _queue) {         thread.sleep(i);     }     thread.sleep(new random().next(0, 3000)); } 

you'd call startthreads() once somewhere, rather calling other startnewthread() method multiple times. presumably, before while (true) loop mentioned.

then need process task, add data queue, e.g.:

_queue.add(_rnd.next(0, 3000)); 

when want threads exit (e.g. after main loop exits, happens):

_queue.completeadding(); 

that cause each of foreach loops in progress end, letting each thread exit.

of course, t type parameter blockingcollection<t> can anything. presumably, whatever in case represents "task". used int, because "task" in example (i.e. number of milliseconds thread should sleep).

then main thread can whatever does, calling add() method dispatch new work consumer threads needed.

again, without more details can't comment on whether approach better using 1 of built-in task-running mechanisms in .net. should work well, given you've explained far.


Comments

Popular posts from this blog

c++ - No viable overloaded operator for references a map -

java - Custom OutputStreamAppender not run: LOGBACK: No context given for <MYAPPENDER> -

java - Cannot secure connection using TLS -