An object of type CpuTimeLimit
may be used to "limit" the CPU time
taken by a computation: if the computation takes too long then an
exception (of type InterruptedByTimeout
) is thrown.
More precisely, when creating a CpuTimeLimit
object you must specify
a time limit in seconds (as a positive double
); there is currently an
upper limit of one million seconds. You must yourself explicitly check
whether the time limit has been reached by calling the member function
operator()
. This call checks whether the allowed time has been
exceeded: if not, it just returns; otherwise it throws an exception
of type TimeoutException
(derived from CoCoA::ErrorInfo
).
IMPORTANT CoCoALib checks for timeout only when the member
function CheckForTimeout::operator()
is called. So it is possible
that CoCoALib does not immediately "notice" that timeout has occurred;
this depends on how often operator()
is called.
There is one real constructor, and one pseudo-constructor:
CpuTimeLimit(seconds)
where seconds
is a positive double
; the measurement of CPU use begins immediately
NoCpuTimeLimit()
returns a CpuTimeLimit
object which has infinite timeout
Let CheckForTimeout
be an object of type CpuTimeLimit
.
There are two operations:
CheckForTimeout(context)
-- does nothing unless timeout has occurred, when it throws a TimeoutException
object; context
is a string literal which is copied into the "context" field of the exception
CheckForTimeout.myPrepareForNewLoop()
-- if the same CpuTimeLimit
object is to be used inside more than one loop, then call this before every loop (except the first one)
IsUnlimited(CheckForTimeout)
-- return true
iff CheckForTimeout
was created by NoCpuTimeLimit
There is one class for exceptions:
TimeoutException(context)
-- the arg context
is a string literal indicating where the timeout was detected (usually it is a good idea to use the name of the function which was interrupted)
The class TimeoutException
derives from ErrorInfo
.
This is the third design. The first was based on SIGVTALRM, but it was not
clear how portable that would be. The second was based on
CheckForInterrupt
, but the calls to CpuTime
were too costly (and it
depended on a global variable). So this new, third design is based on
ProgressReporter
: it assumes that the times between successive clock
checks do not vary too much.
The idea is to check the actual cpu time only occasionally, and not every
time operator()
is called. It uses a similar strategy to that of
ProgressReporter
which assumes that calls to operator()
occur at
fairly regular intervals.
The private data field myDoCheckAtThisCount
has a special role
if its value is zero: it means that the CpuTimeLimit
object has
infinite timeout, so should never check cpu usage.
Perhaps arrange for myDoCheckAtThisCount
to be reduced when
getting close to myTriggerTime
?
Inconvenient having to pass CpuTimeLimit
as explicit parameters;
but how else to do this in a threadsafe way?
A normal call to CpuTime()
may not work as desired in a multithreaded
context. It is not clear how to solve this portably.
2018