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 double
); there is currently an upper
limit of one million seconds. When the CpuTimeLimit
object is destroyed
or deactivated the allowed time becomes unlimited.
IMPORTANT CoCoALib checks for timeout only when the function
CheckForTimeout
is called; note that CheckForInterrupt
calls
CheckForTimeout
if no signal has been registered, see interrupt
.
So it is possible that CoCoALib does not immediately "notice" that timeout
has occurred; this depends on how often CheckForTimeout
is called.
There is just one constructor:
CpuTimeLimit(seconds)
where seconds
is a positive double
; monitoring of CPU use begins immediately
Monitoring of CPU use continues until the CpuTimeLimit
object is destroyed of deactivated (see below).
There are two operations:
CheckForTimeout(context)
-- does nothing unless timeout has occurred, wen it throws a InterruptedByTimeout
object; context
is a string literal
deactivate(CpuLimiter)
-- stops checking whether the CPU time is within limit
There is one class for exceptions:
InterruptedByTimeout(context)
-- the arg context
is a string literal indicating where the timeout was detected (usually the name of the function which was interrupted)
The class InterruptedByTimeout
derives from InterruptReceived
.
The main design idea is just to use a global variable called
CPU_TIME_LIMIT
(of type double
) to store the CPU time
when timeout will occur. THIS IS PROBABLY NOT THREADSAFE
If CPU_TIME_LIMIT
is zero then there is no time limit.
The value of CPU_TIME_LIMIT
is set by the ctor for CpuTimeLimit
,
and reset by the destructor. In the ctor, if there is already a timeout
and the new timeout would occur after the existing one then the new
timeout is reduced to be equal to the existing one.
An object of type CpuTimeLimit
may be either "active" or "deactivated":
the data member myPrevExpirationTime
is mad negative when the object
becomes deactivated (see mem fn myDeactivate
). Deactivation stops
the process of checking CPU time: it restores CPU_TIME_LIMIT
to its
previous value. The dtor simply deactivates the object, then returns.
The data member myExpirationTime
contains the max value which CpuTime()
may attain before timeout is deemed to have occurred. Since timeout is
noticed only when CheckForTimeout
is called, the actual value of CpuTime()
will be higher than the limit in myExpirationTime
. The time difference may
potentially be quite large.
The data member myPrevExpirationTime
plays several roles:
CpuTimeLimit
object has been deactivated
CpuTimeLimit
object was created
The data member myPrevExpirationTime
is used in the mem fn myDeactivate
to restore CPU_TIME_LIMIT
to its previous value.
New design seems to be cleaner than the SIGVTALRM-based first version.
The penalty is the increased cost of CheckForInterrupt
(which has
to call CheckForTimeout
).
I'm not sure how costly/inconvenient repeated calls to CpuTime()
are.
This design requires them.
Unlikely to be truly threadsafe.
2017