Happy New Year Rob and everyone else,
On 09/01/2025 22:02, Rob Arthan wrote:
Happy New Year to the Poly/ML User Community!
I am trying to find a fix to a problem where we want to apply a function
that sometimes takes far too long to execute. So I want to abort execution of
the function after a specified time limit. I have a solution that seems to work
by forking a worker thread to execute the function and store the result in a
ref while
the control thread goes into a loop that waits for 100ms and then either (1)
returns the
result from the ref if the worker thread is no longer active, (2) repeats if
the thread
is still active and we haven’t reaced the time limit or otherwise (3) kills the
worker thread
and returns a dummy value.
I am implementing this using Thread.ConditionVar.waitUntil and have two
questions
about that:
1) What does the bool returned by Thread.ConditionVar.waitUntil mean? That
doesn’t seem
to be documented.
This indicates whether the wait has returned because the condition
variable was signalled (true) or because it timed out (false).
2) In addition to the timeout, Thread.ConditionVar.waitUntil has a condition
variable and a mutex
as arguments. I am just creating these using Thread.ConditionVar.conditionVar
and Thread.Mutex.mutex
because I need some values to pass to Thread.ConditionVar.waitUntil. I am not
doing any signalling
or locking or unlocking. Is that going to cause any problems? (The condition
variable and the mutex
are local to the control thread function, so the worker thread function has no
access to them.)
This is a standard paradigm but you do need to follow the rules if you
want it to work properly.
The condition variable and mutex need to be shared between the two threads.
In the worker thread:
When you're ready to return a result:
Disable asynchronous interrupts if they're enabled,
Lock the mutex,
Store the result in the shared reference,
Signal the condition variable,
Unlock the mutex,
Re-enable the asynchronous interrupts if you're continuing to process
Or exit
In the control thread:
Disable asynchronous interrupts if necessary,
Lock the mutex,
Start of loop:
Read the shared reference. If the worker has stored the result, unlock
the mutex, restore interrupts and exit the loop,
Wait on the condition variable and mutex,
Go to the start of the loop.
It's important that the worker thread locks the mutex for two reasons.
It avoids any race conditions which could occur if the worker thread set
the shared reference and signalled the condition variable in the time
between the control thread deciding that the result had not been stored
yet and blocking on the condition variable. That's not too much of a
problem if you're using waitUntil with a short interval. More
importantly, locking and unlocking the mutex also puts in memory
barriers which are essential on machines such as the ARM with relaxed
memory ordering. Without some sort of interlock between the worker
thread and the control thread there is no guarantee that the control
thread will ever see that the shared reference has been updated.
It's better to use Thread.interrupt rather than Thread.kill since it
allows the worker thread to handle the Interrupt exception and free up
resources where necessary and also to mask the exception in critical
sections. The worker thread needs to be created with InterruptState
InterruptAsynch for this to work or to set that with
Thread.setAttributes once it is running.
David
_______________________________________________
polyml mailing list
[email protected]
http://lists.inf.ed.ac.uk/mailman/listinfo/polyml