开发者

How would I make a thread join on another thread but only wait for n seconds of CPU time?

otherThread.join( time ) appears to wait time in real milliseconds. I want to wait time in actual CPU time so that I can get consistent behavior within my application.

I've done a quick look at ThreadMXBean but that doesn't quite seem to have what I wanted ( it tells me the threads actual CPU time, but offers no convenient way to wait until some time has passed ) . A busy loop around a sleep() could work, but seems grossly inefficient.

I also thought about using another thread and waiting on a Condition, but I'm not sure how that would work. The main thread would do: myCondition.await() , where another thread that would toggle myCondition when otherThread had used time actual CPU time. Again, this seems complicated and would probably still require the controlling thread to have a busy loop.

Edit: I'm doing this for a grading script. This means that I need to have a way to timeout if the student is in an infinite loop and it needs to be fair. I've been using JUnit to run tests on students, but that has the same problem with timing out: if the same (inefficient) submission is run multiple times, it could possibly get different grades depending on what other jobs are running on the 开发者_开发知识库machine at the time (a real problem for group work).

But this is a problem with normal unit testing, too - by using clock time instead of CPU time JUnit gets inconsistent test results?


I'd suggest running a single JVM test at a time, and using time (see man time for details) to determine actual CPU time used. As for interrupting it if it takes too long... You could probably accomplish that with a shell script, or just allow the process to run to completion and base grading on the actual time taken.


Not going to happen. A timed join() is based on wall clock time, which means a hardware timer can be set to provide an asynchronous interrupt x seconds from now if the thread hasn't already been exited. Since there's no way to know a priori how much CPU a thread will use and therefore no way to schedule an interrupt when some boundary is reached. CPU time is accounted for when a process yields its time slice voluntarily or by force, so there wouldn't be any way to hit some exact figure anyway.

The closest you'd be able to get is polling the CPU utilization every so often and invoking interrupt() on threads that have gone over the limit. (Study the semantics of that carefully, because interrupting a thread will not necessarily bring the thread to an immediate stop.) If all you care about is whether or not the thread has consumed more than x seconds of CPU time, late checks that get results like kx where k > 1 aren't going to matter. They're still greater than x, and that's enough to know your candidate went over the limit.

One thing you could do if you're on a Unix-y system is to run the entire assignment as a process and use ulimit to limit the amount of CPU it's allowed to some value with a reasonable amount tacked on for JVM startup and program load.


Think about what you're asking for: you want a thread to block (not use CPU time) until it has used a specified amount of CPU time. This doesn't make sense.

I suspect what you really want if for your thread to block until another thread has used a specified amount of CPU time. This is not easily provided, probably because it is so rarely useful and can lead you down paths to poorly behaving code.


I think if you combine thread.join()/interrupt() strategy (for timing out bad code (infinite loops)) and testingThread calling back cpu time you get what you want, if I´m not missing something. The solution may follow an approach like:

public class GradingThread extends Thread {
    private Thread testThread;
    private long elapsedClockTime=-1;
    public GradingThread(TestingThread testThread){
        this.testThread = testThread;
        testThread.setGradingThread(this);
    }
    public void setElapsed(long elapsedClockTime){
        this.elapsedClockTime = elapsedClockTime;
    }
    public void run(){
        System.out.println("GradingThread ID="+Thread.currentThread().getId());
        try{
        testThread.start();
        testThread.join(5000);
        testThread.interrupt();
        }catch(Exception e){e.printStackTrace();}
        if(elapsedClockTime==-1){
            System.out.println("Student program timedout (more than 5000 clock seconds)");
        }else{
            System.out.println("Student program elapsed cpu time = "+(elapsedClockTime)/1000000+"ms");
        }
    }
    public static void main(String[] args) {
        (new GradingThread(new TestingThread())).start();
    }
}
public class TestingThread extends Thread {
    private GradingThread gradingThread;
    public void setGradingThread(GradingThread thread){
        gradingThread = thread;
    }
    public void run(){
        StudentProgram sp = new StudentProgram();
        System.out.println("TestingThrad ID="+Thread.currentThread().getId());
        long scpu = getCpuTime();
            sp.takeLessThan5WallSecondsToRun(); //try calling infiniteLoop() too.
        long ecpu = getCpuTime();
        gradingThread.setElapsed(ecpu - scpu);
    }
    /** Get CPU time in nanoseconds. */
    public long getCpuTime( ) {
        ThreadMXBean bean = ManagementFactory.getThreadMXBean( );
        if ( ! bean.isCurrentThreadCpuTimeSupported())
            return -1L;
        long time = bean.getThreadCpuTime(Thread.currentThread().getId());       
        return time;
    }
}//end of TestingThread.
class StudentProgram {
    public void infiniteLoop(){
        while(true);
    }
    public int takeLessThan5WallSecondsToRun(){
        int total=0;
        while(total < Integer.MAX_VALUE) total++;
        return total;   
    }
}//end of StudentProgram.
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜