java - Pause thread from another thread(s) and also stop/start it yet from another thread -
i've found good hints here. have more difficult task - additional requests are:
- low priority forever thread can started/stopped main thread (that's same) - has lock 1 resource exclusive access.
- low priority forever thread can paused/continued high priority thread(s) (they lock , use 1 resource)
- want low priority thread not release lock in each loop, release lock once told (for speed purposes - cos need init/deinit resource) (if have release lock every loop may let java manage competing threads , expect high priority threads win every , then).
i come solution , think safe , sound. i'm newbie i'm open finding bug in solution or suggestions improvements. questions are:
1) solution thread safe in cases?
2) optimal solution or can improve something?
if agreed let used template.
here core code:
flagnotify lowpriorrunreq = new flagnotify(false); // low priority task run request flagnotify lowpriorpausereq = new flagnotify(false); // low priority task pause request (it uses notify) volatile boolean lowpriorrunflag = false; // low priority task run flag lock grouplock = new reentrantlock(); // group lock (used acquire lowpriorrunflag correctly) semaphore resourcesemaphore = new semaphore(1); // main semaphore protecting resource has accessed sequentially public class prioritysingletaskthread extends thread { @override public void run() { prn("high priority task created"); grouplock.lock(); if(lowpriorrunflag == true) lowpriorpausereq.setnotify(true); resourcesemaphore.acquireuninterruptibly(); grouplock.unlock(); accessresource("high priority task"); resourcesemaphore.release(); grouplock.lock(); if(lowpriorpausereq.get() == true) lowpriorpausereq.setnotify(false); grouplock.unlock(); prn("high priority task closed"); } } public class lowprioritycontinuousthread extends thread { void getresourcesemaphore(){ grouplock.lock(); resourcesemaphore.acquireuninterruptibly(); lowpriorrunflag = true; grouplock.unlock(); accessresource("low priority init"); // here initialization , want happen on request priority thread } void releaseresourcesemaphore(){ accessresource("low priority de-init"); // here de-initialization , want happen on request priority thread lowpriorrunflag = false; resourcesemaphore.release(); } @override public void run() { while(true){ //prn("low priority run req: "+lowpriorrunreq.get()); if(lowpriorrunreq.get() == true && lowpriorrunflag == false){ prn("low priority task starting"); getresourcesemaphore(); prn("low priority task started"); } if(lowpriorrunreq.get() == false && lowpriorrunflag == true){ prn("low priority task stopping"); releaseresourcesemaphore(); prn("low priority task stopped"); lowpriorrunreq.smartwait(true); } // note keep checking lowpriorrunflag. imagine there runflag detected high priority thread // before de-asserted, pausereq requested high priority thread // resource released when low priority task stops. // high priority lock , use resource, since pausereq set // thread try access device in order de-init , pause (unless check runflag) if(lowpriorpausereq.get() == true && lowpriorrunflag == true){ prn("low priority task pausing"); releaseresourcesemaphore(); prn("low priority task paused"); lowpriorpausereq.smartwait(false); getresourcesemaphore(); prn("low priority task continue"); } if(lowpriorrunflag){ accessresource("low priority task"); } } } }
and here full compilable java code including test bench (so have hint safe solution - never know threads)
import java.util.concurrent.semaphore; import java.util.concurrent.atomic.atomicinteger; import java.util.concurrent.locks.lock; import java.util.concurrent.locks.reentrantlock; public class main { // inner class setting flag , waiting notify - not hog cpu public class flagnotify{ private boolean flag; // not synchro on boolean - immutable, new object created every value change.... private object synchro = new object(); public flagnotify(boolean val) { flag = val; } public void setnotify(boolean val) { synchronized (synchro) { flag = val; synchro.notify(); } } public boolean get(){ return flag; } public void smartwait(boolean expval){ synchronized (synchro){ while(flag != expval){ try { synchro.wait(); } catch (interruptedexception e) { e.printstacktrace(); } } } } } flagnotify lowpriorrunreq = new flagnotify(false); // low priority task run request flagnotify lowpriorpausereq = new flagnotify(false); // low priority task pause request (it uses notify) volatile boolean lowpriorrunflag = false; // low priority task run flag lock grouplock = new reentrantlock(); // group lock (used acquire lowpriorrunflag correctly) semaphore resourcesemaphore = new semaphore(1); // main semaphore protecting resource has accessed sequentially public class prioritysingletaskthread extends thread { @override public void run() { prn("high priority task created"); grouplock.lock(); if(lowpriorrunflag == true) lowpriorpausereq.setnotify(true); resourcesemaphore.acquireuninterruptibly(); grouplock.unlock(); accessresource("high priority task"); resourcesemaphore.release(); grouplock.lock(); if(lowpriorpausereq.get() == true) lowpriorpausereq.setnotify(false); grouplock.unlock(); prn("high priority task closed"); } } public class lowprioritycontinuousthread extends thread { void getresourcesemaphore(){ grouplock.lock(); resourcesemaphore.acquireuninterruptibly(); lowpriorrunflag = true; grouplock.unlock(); accessresource("low priority init"); // here initialization , want happen on request priority thread } void releaseresourcesemaphore(){ accessresource("low priority de-init"); // here de-initialization , want happen on request priority thread lowpriorrunflag = false; resourcesemaphore.release(); } @override public void run() { while(true){ //prn("low priority run req: "+lowpriorrunreq.get()); if(lowpriorrunreq.get() == true && lowpriorrunflag == false){ prn("low priority task starting"); getresourcesemaphore(); prn("low priority task started"); } if(lowpriorrunreq.get() == false && lowpriorrunflag == true){ prn("low priority task stopping"); releaseresourcesemaphore(); prn("low priority task stopped"); lowpriorrunreq.smartwait(true); } // note keep checking lowpriorrunflag. imagine there runflag detected high priority thread // before de-asserted, pausereq requested high priority thread // resource released when low priority task stops. // high priority lock , use resource, since pausereq set // thread try access device in order de-init , pause (unless check runflag) if(lowpriorpausereq.get() == true && lowpriorrunflag == true){ prn("low priority task pausing"); releaseresourcesemaphore(); prn("low priority task paused"); lowpriorpausereq.smartwait(false); getresourcesemaphore(); prn("low priority task continue"); } if(lowpriorrunflag){ accessresource("low priority task"); } } } } //------------------------------------------------------------------------- //-- following functions meant testing atomicinteger clashdetector = new atomicinteger(0); // testing purposes public void accessresource(string from){ prn("resource used "+from); if(clashdetector.addandget(1)>1){ system.out.println("clash detected - bad programmer :(((((("); system.exit(-1); } sleeprandom(5); clashdetector.getandadd(-1); } public void sleeprandom(long maxmilisec){ mysleep((long)(math.random()*maxmilisec)); } public void mysleep(long milisec){ try{ thread.sleep(milisec); }catch (interruptedexception e) { e.printstacktrace(); } } void prn(string s){ system.out.println(s); } public void test(){ new lowprioritycontinuousthread().start(); for(long i=0; i< (long)1e3; i++){ lowpriorrunreq.setnotify(true); for(int j=0; j<math.random()*100;j++){ sleeprandom(10); new prioritysingletaskthread().start(); } //sleeprandom(20); lowpriorrunreq.setnotify(false); for(int j=0; j<math.random()*20;j++){ sleeprandom(10); new prioritysingletaskthread().start(); } //sleeprandom(20); } mysleep(200); system.out.println("test ok :)))))))))))))))))))))"); mysleep(200); system.exit(0); } public static void main(string[] args) throws exception { new main().test(); } }
i don't know means "start/stop" "forever thread", 1 design pattern can use pausing thread called "turnstile". here's 1 works when there 1 controller thread allowed "lock" or "unlock" turnstile:
import java.util.concurrent.semaphore; class turnstile { private final semaphore semaphore = semaphore.new(1); // called "controller" thread. public void lock() { semaphore.acquire(); } // called "controller" thread. public void unlock() { semaphore.release(); } // called worker threads. public void passthrough() { semaphore.lock(); semaphore.release(); } }
initially, turnstile in "unlocked" state, , passthrough() method promptly returns when ever worker calls it. if master thread "locks" turnstile, worker calls passthrough() blocked until master "unlocks" again. then, of workers "pass through", one-by-one.
you modify example if want have more 1 "master", it's decide how resolve conflict when 1 master wants turnstile locked, , wants unlocked.
then again, instead of modifying turnstile
, write new multimasterturnstile
handles conflict resolution , uses turnstile
block workers.
Comments
Post a Comment