_disable_threads
_disable_threads()
This function first posts a notice to all threads that it is time to halt. It then waits until all threads actually have halted, and then then returns a lock object. All other threads will be blocked from running until that object has been freed/destroyed.
It's mainly useful to do things that require a temporary uid/gid change, since on many OSes the effective user and group apply to all threads.
You should make sure that the returned object is freed even if some kind of error is thrown. That means in practice that it should only have references (direct or indirect) from function local variables. Also, it shouldn't be referenced from cyclic memory structures, since those are only destructed by the periodic gc. (This advice applies to mutex locks in general, for that matter.)
gethrdtime()
This module contains classes and functions for interacting and synchronizing with threads.
For convenience some of the classes here are emulated (and are thus available) when threads are not supported.
Some of the classes that have such fallbacks are: Condition
,
Fifo
, Local
, Mutex
, MutexKey
and Queue
.
Thread
, Mutex
, Condition
constant
Thread.MUTEX_SUPPORTS_SHARED_LOCKS
Recognition constant for support of shared locks.
If this symbol exists and is not 0
then the Mutex
class
supports shared locks (ie has Mutex()->shared_lock()
et al).
array
(Thread.Thread
) all_threads()
This function returns an array with the thread ids of all threads.
Thread()
int(0..)
get_thread_quanta()
Returns the current thread quanta in nanoseconds.
set_thread_quanta()
, gethrtime()
int(0..)
set_thread_quanta(int(0..)
ns
)
Set the thread quanta.
ns
New thread quanta in nanoseconds. A value of zero (default) disables the thread quanta checks.
When enabled MasterObject.thread_quanta_exceeded()
will
be called when a thread has spent more time than the quanta
without allowing another thread to run.
Setting a non-zero value that is too small to allow for
MasterObject.thread_quanta_exceeded()
to run is NOT a
good idea.
Returns the previous thread quanta in nanoseconds.
set_thread_quanta()
, gethrtime()
Thread.Thread
this_thread()
This function returns the object that identifies this thread.
Thread()
void
thread_set_concurrency(int
concurrency
)
Document this function
Implementation of condition variables.
Condition variables are used by threaded programs to wait for events happening in other threads.
In order to prevent races (which is the whole point of condition variables), the modification of a shared resource and the signal notifying modification of the resource must be performed inside the same mutex lock, and the examining of the resource and waiting for a signal that the resource has changed based on that examination must also happen inside the same mutex lock.
Typical wait operation:
Take mutex lock
Read/write shared resource
Wait for the signal with the mutex lock in released state
Reacquire mutex lock
If needed, jump back to step 2 again
Release mutex lock
Typical signal operation:
Take mutex lock
Read/write shared resource
Send signal
Release mutex lock
You have some resource that multiple treads want to use. To protect this resource for simultaneous access, you create a shared mutex. Before you read or write the resource, you take the mutex so that you get a consistent and private view of / control over it. When you decide that the resource is not in the state you want it, and that you need to wait for some other thread to modify the state for you before you can continue, you wait on the conditional variable, which will temporarily relinquish the mutex during the wait. This way a different thread can take the mutex, update the state of the resource, and then signal the condition (which does not in itself release the mutex, but the signalled thread will be next in line once the mutex is released).
Condition variables are only available on systems with thread support. The Condition class is not simulated otherwise, since that can't be done accurately without continuations.
Signals may currently be sent without holding the lock, but this should be avoided as it may cause the signal to be lost (especially when the signal is not associated with a corresponding change of the shared resource).
Mutex
void
broadcast()
broadcast()
wakes up all threads currently waiting for this condition.
signal()
Thread.Condition Thread.Condition(
Thread.Mutex
|void
mutex
)
mutex
Optional Mutex
that protects the resource that the
condition signals for.
void
signal()
signal()
wakes up one of the threads currently waiting for the
condition.
Sometimes more than one thread is woken up.
broadcast()
void
wait(Thread.MutexKey
mutex_key
)
void
wait(Thread.MutexKey
mutex_key
, int(0..)
|float
seconds
)
void
wait(Thread.MutexKey
mutex_key
, int(0..)
seconds
, int(0..999999999)
nanos
)
Wait for condition.
This function makes the current thread sleep until the condition variable is signalled or the timeout is reached.
mutex_key
A Thread.MutexKey
object for a Thread.Mutex
. It will be
unlocked atomically before waiting for the signal and then
relocked atomically when the signal is received or the timeout
is reached. Note that it MUST be an exclusive lock.
seconds
Seconds to wait before the timeout is reached.
nanos
Nano (1/1000000000) seconds to wait before the timeout is reached.
This value is added to the number of seconds specified by seconds
.
A timeout of zero seconds disables the timeout.
The thread that sends the signal should have the mutex locked
while sending it. Otherwise it's impossible to avoid races where
signals are sent while the listener(s) haven't arrived to the
wait
calls yet.
The support for timeouts was added in Pike 7.8.121, which was after the first public release of Pike 7.8.
Note that the timeout is approximate (best effort), and may be exceeded if eg the mutex is busy after the timeout.
Note also that any threads waiting on the condition will be woken up when it gets destructed.
Mutex->lock()
A thread farm.
8.0::Thread.Farm
string
debug_status()
Get some statistics for the thread farm.
Concurrent.Future
run(function
(:void
) f
, mixed
... args
)
Register a job for the thread farm.
f
Function to call with @args
to
perform the job.
args
The parameters for f
.
Returns a Result
object for the job.
In Pike 7.8 and earlier this function
was broken and returned a Result
object that wasn't connected to the job.
run_async()
void
run_async(function
(:void
) f
, mixed
... args
)
Register a job for the thread farm
where the return value from f
is
ignored.
f
Function to call with @args
to
perform the job.
args
The parameters for f
.
run()
Concurrent.Future
run_multiple(array
(array
(function
(:void
)|array
)) fun_args
)
Register multiple jobs.
fun_args
An array of arrays where the first element is a function to call, and the second is a corresponding array of arguments.
Returns a Concurrent.Future
object with an array
with one element for the result for each
of the functions in fun_args
.
Do not modify the elements of fun_args
before the result is available.
If any of the functions in fun_args
throws
and error, all of the accumulated results
(if any) will be dropped from the result, and
the first backtrace be provided.
run_multiple_async()
void
run_multiple_async(array
fun_args
)
Register multiple jobs where the return values are to be ignored.
fun_args
An array of arrays where the first element is a function to call, and the second is a corresponding array of arguments.
Do not modify the elements of fun_args
before the result is available.
run_multiple()
int
set_max_num_threads(int(1..)
to
)
Set the maximum number of worker threads that the thread farm may have.
to
The new maximum number.
If there are more worker threads than to
,
the function will wait until enough threads
have finished, so that the total is to
or less.
The default maximum number of worker threads is 20
.
void
set_thread_name_cb(function
(object
, string
:void
) cb
, void
|string
prefix
)
Provide a callback function to track names of threads created by the farm.
cb
The callback function. This will get invoked with the thread as the
first parameter and the name as the second whenever a thread is
created. When the same thread terminates the callback is invoked
again with 0
as the second parameter. Set cb
to 0
to stop
any previously registered callbacks from being called.
prefix
An optional name prefix to distinguish different farms. If not given a prefix will be generated automatically.
A worker thread.
string
debug_status()
Get some statistics about the worker thread.
object
Thread.Farm.ValueAdjuster.r
object
Thread.Farm.ValueAdjuster.r2
int
Thread.Farm.ValueAdjuster.i
mapping
Thread.Farm.ValueAdjuster.v
protected
local
void
__create__(object
r
, object
r2
, int
i
, mapping
v
)
Thread.Farm.ValueAdjuster Thread.Farm.ValueAdjuster(
object
r
, object
r2
, int
i
, mapping
v
)
Fifo
implements a fixed length first-in, first-out queue.
A fifo is a queue of values and is often used as a stream of data
between two threads.
Queue
inherit Mutex : lock
inherit Condition : r_cond
inherit Condition : w_cond
Thread.Fifo Thread.Fifo()
Thread.Fifo Thread.Fifo(
int
size
)
Create a fifo. If the optional size
argument is present it
sets how many values can be written to the fifo without blocking.
The default size
is 128.
mixed
peek()
This function returns the next value in the fifo if there are
any there. If there are no values present in the fifo then
UNDEFINED
will be returned.
read()
, try_read()
mixed
read()
This function retrieves a value from the fifo. Values will be returned in the order they were written. If there are no values present in the fifo the current thread will sleep until some other thread writes one.
peek()
, try_read()
, read_array()
, write()
array
read_array()
This function returns all values in the fifo as an array. The values in the array will be in the order they were written. If there are no values present in the fifo the current thread will sleep until some other thread writes one.
read()
, try_read_array()
int
size()
This function returns the number of elements currently in the fifo.
read()
, write()
mixed
try_read()
This function retrieves a value from the fifo if there are any
there. Values will be returned in the order they were written.
If there are no values present in the fifo then UNDEFINED
will be returned.
peek()
, read()
array
try_read_array()
This function returns all values in the fifo as an array but doesn't wait if there are no values there. The values in the array will be in the order they were written.
read_array()
int
try_write(mixed
value
)
Append a value
to the end of the fifo. If there is no more
room in the fifo then zero will be returned, otherwise the
number of items in the fifo after the write is returned.
read()
int
write(mixed
value
)
Append a value
to the end of the fifo. If there is no more
room in the fifo the current thread will sleep until space is
available. The number of items in the queue after the write is
returned.
read()
Thread local variable storage.
This class allows you to have variables which are separate for each
thread that uses it. It has two methods: get()
and set()
. A value
stored in an instance of Local
can only be retrieved by that
same thread.
This class is simulated when Pike is compiled without thread support, so it's always available.
__generic__
mixed
ValueType
= mixed
Type for the value to be stored in the thread local storage.
ValueType
get()
Get the thread local value.
This returns the value prevoiusly stored in the Local
object by
the set()
method by this thread.
set()
ValueType
set(ValueType
value
)
Set the thread local value.
This sets the value returned by the get
method.
Calling this method does not affect the value returned by get()
when
it's called by another thread (ie multiple values can be stored at the
same time, but only one value per thread).
This function returns its argument.
Note that the value set can only be retreived by the same thread.
get()
Mutex
is a class that implements mutual exclusion and shared locks.
Mutex locks are used to prevent multiple threads from simultaneously executing sections of code which access or change shared data. The basic operations for a mutex is locking and unlocking. If a thread attempts to lock an already locked mutex the thread will sleep until the mutex is unlocked.
This class is simulated when Pike is compiled without thread support, so it's always available.
Support for shared locks was added in Pike 8.1.14.
In POSIX threads, mutex locks can only be unlocked by the same thread that locked them. In Pike any thread can unlock a locked mutex.
string sprintf(string format, ... Thread.Mutex arg ... )
Describes the mutex including the thread that currently holds the lock (if any).
Condition
cond()
Create a Condition
.
This function is equivalent to
Thread.Condition(mux);
Condition
Thread.MutexKey
current_locking_key()
This mutex method returns the key object currently governing the lock on this mutex. 0 is returned if the mutex isn't locked.
Thread()
Thread.Thread
current_locking_thread()
This mutex method returns the object that identifies the thread that has locked the mutex. 0 is returned if the mutex isn't locked.
Thread()
Concurrent.Future
future_lock()
This function is similar to lock()
, but will return
a Concurrent.Future(<Thread.MutexKey>)
that will
complete successfully when the Mutex
is locked.
Avoid having multiple future_lock
's for different Mutex
es
pending concurrently in the same conceptual thread as this will
likely cause dead-locks.
Concurrent.Future
future_shared_lock()
This function is similar to shared_lock()
, but will return
a Concurrent.Future(<Thread.MutexKey>)
that will
complete successfully when the Mutex
is locked.
Avoid having multiple future_shared_lock
's for different Mutex
es
pending concurrently in the same conceptual thread as this will
likely cause dead-locks.
MutexKey
lock()
MutexKey
lock(int
type
)
MutexKey
lock(int
type
, int(0..)
|float
seconds
)
MutexKey
lock(int
type
, int(0..)
seconds
, int(0..999999999)
nanos
)
This function attempts to lock the mutex. If the mutex is already locked by a different thread the current thread will sleep until the mutex is unlocked. The value returned is the 'key' to the lock. When the key is destructed or has no more references the mutex will automatically be unlocked.
The type
argument specifies what lock()
should do if the
mutex is already locked by this thread:
| Throw an error. |
| Sleep until the mutex is unlocked. Useful if some other thread will unlock it. |
| Return zero. This allows recursion within a locked region of code, but in conjunction with other locks it easily leads to unspecified locking order and therefore a risk for deadlocks. |
seconds
Seconds to wait before the timeout is reached.
nanos
Nano (1/1000000000) seconds to wait before the timeout is reached.
This value is added to the number of seconds specified by seconds
.
A timeout of zero seconds disables the timeout.
Returns a MutexKey
on success and 0
(zero) on timeout.
The support for timeouts was added in Pike 8.1.14, which was before the first public release of Pike 8.1.
Note that the timeout is approximate (best effort), and may be exceeded if eg the interpreter is busy after the timeout.
If the mutex is destructed while it's locked or while threads are
waiting on it, it will continue to exist internally until the last
thread has stopped waiting and the last MutexKey
has
disappeared, but further calls to the functions in this class will
fail as is usual for destructed objects.
Pike 7.4 and earlier destructed any outstanding lock when the
mutex was destructed, but threads waiting in lock
still got
functioning locks as discussed above. This is inconsistent no
matter how you look at it, so it was changed in 7.6. The old
behavior is retained in compatibility mode for applications that
explicitly destruct mutexes to unlock them.
trylock()
MutexKey
shared_lock()
MutexKey
shared_lock(int
type
)
MutexKey
shared_lock(int
type
, int(0..)
|float
seconds
)
MutexKey
shared_lock(int
type
, int(0..)
seconds
, int(0..999999999)
nanos
)
This function attempts to lock the mutex. If the mutex is already locked by a different thread the current thread will sleep until the mutex is unlocked. The value returned is the 'key' to the lock. When the key is destructed or has no more references the mutex will automatically be unlocked.
The type
argument specifies what lock()
should do if the
mutex is already locked exclusively by this thread:
| Throw an error. |
| Sleep until the mutex is unlocked. Useful if some other thread will unlock it. |
| Return zero. This allows recursion within a locked region of code, but in conjunction with other locks it easily leads to unspecified locking order and therefore a risk for deadlocks. |
seconds
Seconds to wait before the timeout is reached.
nanos
Nano (1/1000000000) seconds to wait before the timeout is reached.
This value is added to the number of seconds specified by seconds
.
A timeout of zero seconds disables the timeout.
Returns a MutexKey
on success and 0
(zero) on timeout.
Note that the timeout is approximate (best effort), and may be exceeded if eg the interpreter is busy after the timeout.
Note that if the current thread already holds a shared key,
a new will be created without waiting, and regardless of
the value of type
.
If the mutex is destructed while it's locked or while threads are
waiting on it, it will continue to exist internally until the last
thread has stopped waiting and the last MutexKey
has
disappeared, but further calls to the functions in this class will
fail as is usual for destructed objects.
Support for shared keys was added in Pike 8.1.
lock()
, trylock()
, try_shared_lock()
MutexKey
try_shared_lock()
MutexKey
try_shared_lock(int
type
)
This function performs the same operation as shared_lock()
,
but if the mutex is already locked exclusively, it will return
zero instead of sleeping until it's unlocked.
Support for shared keys was added in Pike 8.1.
shared_lock()
, lock()
, trylock()
MutexKey
trylock()
MutexKey
trylock(int
type
)
This function performs the same operation as lock()
, but if the mutex
is already locked, it will return zero instead of sleeping until it's
unlocked.
lock()
Objects of this class are returned by Mutex()->lock()
and Mutex()->trylock()
et al. They are also passed as arguments
to Condition()->wait()
.
As long as they are held, the corresponding mutex will be locked.
The corresponding mutex will be unlocked when the object is destructed (eg by not having any references left).
Mutex
, Condition
string sprintf(string format, ... Thread.MutexKey arg ... )
void
downgrade()
Downgrade an exclusive lock into a shared lock.
A downgraded lock may be upgraded back to an exclusive lock
by calling upgrade()
or try_upgrade()
.
upgrade()
, try_upgrade()
bool
try_upgrade()
Try to upgrade a downgraded lock into an exclusive lock.
| Returns |
| Returns |
downgrade()
, upgrade()
bool
upgrade()
bool
upgrade(int(0..)
|float
seconds
)
bool
upgrade(int(0..)
seconds
, int(0..999999999)
nanos
)
Upgrade a downgraded lock into an exclusive lock.
seconds
Seconds to wait before the timeout is reached.
nanos
Nano (1/1000000000) seconds to wait before the timeout is reached.
This value is added to the number of seconds specified by seconds
.
A timeout of zero seconds disables the timeout.
Note that the timeout is approximate (best effort), and may be exceeded if eg the interpreter is busy after the timeout.
Waits until all concurrent shared locks are released, and upgrades this lock into being an exclusive lock. Any attempts to make new shared locks will block as soon as this function is called.
downgrade()
, try_upgrade()
Queue
implements a queue, or a pipeline. The main difference
between Queue
and Fifo
is that Queue
will never block in write(), only allocate more memory.
Ought to be made API-compatible with ADT.Queue
.
Fifo
, ADT.Queue
inherit Mutex : lock
inherit Condition : r_cond
mixed
peek()
This function returns the next value in the queue if there are
any there. If there are no values present in the queue then
UNDEFINED
will be returned.
peek()
, read()
, try_read()
, write()
array
peek_array()
Returns a snapshot of all the values in the queue, in the order they were written. The values are still left in the queue, so if other threads are reading from it, the returned value should be considered stale already on return.
mixed
read()
This function retrieves a value from the queue. Values will be returned in the order they were written. If there are no values present in the queue the current thread will sleep until some other thread writes one.
peek()
, try_read()
, write()
array
read_array()
This function returns all values in the queue as an array. The values in the array will be in the order they were written. If there are no values present in the queue the current thread will sleep until some other thread writes one.
read()
, try_read_array()
int
size()
This function returns the number of elements currently in the queue.
read()
, write()
mixed
try_read()
This function retrieves a value from the queue if there are any
there. Values will be returned in the order they were written.
If there are no values present in the queue then UNDEFINED
will be returned.
peek()
, read()
, write()
array
try_read_array()
This function returns all values in the queue as an array but doesn't wait if there are no values there. The values in the array will be in the order they were written.
read_array()
int
write(mixed
value
)
This function puts a value
last in the queue. If the queue is
too small to hold the value
it will be expanded to make room.
The number of items in the queue after the write is returned.
read()
Implements an inverted-semaphore-like resource
counter. A thread can poll or perform a blocking wait for the
resource-count to drop below a certain level
.
ResourceCountKey
, Condition
, Mutex
final
ResourceCountKey
acquire()
Increments the resource-counter.
A ResourceCountKey
to decrement the resource-counter again.
final
bool
drained(void
|int
level
)
level
The maximum level that is considered drained.
True if the resource counter drops to equal or below level
.
final
void
wait_till_drained(void
|int
level
)
Blocks until the resource-counter dips to max level
.
level
The maximum level that is considered drained.
When this key is destroyed, the corresponding resource counter will be decremented.
ResourceCount
, MutexKey
private
inherit __builtin.DestructImmediate : DestructImmediate
string sprintf(string format, ... Thread.Thread arg ... )
Returns a string identifying the thread.
array
(mixed
) backtrace(int
|void
flags
)
Returns the current call stack for the thread.
flags
A bit mask of flags affecting generation of the backtrace.
Currently a single flag is defined:
| Return Note that since these values are "live", they may change or dissapear at any time unless the corresponding thread has been halted or similar. |
The result has the same format as for predef::backtrace()
.
predef::backtrace()
Thread.Thread Thread.Thread(
function
(mixed
... :mixed
|void
) f
, mixed
... args
)
This function creates a new thread which will run simultaneously
to the rest of the program. The new thread will call the function
f
with the arguments args
. When f
returns the thread will cease
to exist.
All Pike functions are 'thread safe' meaning that running a function at the same time from different threads will not corrupt any internal data in the Pike process.
The returned value will be the same as the return value of
this_thread()
for the new thread.
This function is only available on systems with POSIX or UNIX or WIN32 threads support.
Mutex
, Condition
, this_thread()
int
gethrvtime(void
|int
nsec
)
The CPU time consumed by this thread.
predef::gethrvtime()
protected
int
id_number()
Returns an id number identifying the thread.
void
interrupt()
void
interrupt(string
msg
)
Interrupt the thread with the message msg
.
This function causes the thread to throw an error
where the message defaults to "Interrupted.\n"
.
The argument msg
is currently ignored.
Interrupts are asynchronous, and are currently not queued.
Due to the asynchronous nature of interrupts, it may take some time before the thread reacts to the interrupt.
void
kill()
Interrupt the thread, and terminate it.
Interrupts are asynchronous, and are currently not queued.
Due to the asynchronous nature of interrupts, it may take some time before the thread reacts to the interrupt.
int
status()
Returns the status of the thread.
| The thread has not yet started executing. |
| The thread has started and has not yet terminated. |
| The thread has terminated by returning a value from the thread function. |
| The thread has terminated by throwing an uncaught error. |
mixed
wait()
Waits for the thread to complete, and then returns the value returned from the thread function.
Rethrows the error thrown by the thread if it exited by throwing an error.