18. Threads


Method _disable_threads

_disable_threads _disable_threads()

Description

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.

Note

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.)

See also

gethrdtime()

Module Thread

Description

This module contains classes and functions for interacting and synchronizing with threads.

Note

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.

See also

Thread, Mutex, Condition


Constant MUTEX_SUPPORTS_SHARED_LOCKS

constant Thread.MUTEX_SUPPORTS_SHARED_LOCKS

Description

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).


Method all_threads

array(Thread.Thread) all_threads()

Description

This function returns an array with the thread ids of all threads.

See also

Thread()


Method get_thread_quanta

int(0..) get_thread_quanta()

Returns

Returns the current thread quanta in nanoseconds.

See also

set_thread_quanta(), gethrtime()


Method set_thread_quanta

int(0..) set_thread_quanta(int(0..) ns)

Description

Set the thread quanta.

Parameter 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.

Note

Setting a non-zero value that is too small to allow for MasterObject.thread_quanta_exceeded() to run is NOT a good idea.

Returns

Returns the previous thread quanta in nanoseconds.

See also

set_thread_quanta(), gethrtime()


Method this_thread

Thread.Thread this_thread()

Description

This function returns the object that identifies this thread.

See also

Thread()


Method thread_set_concurrency

void thread_set_concurrency(int concurrency)

FIXME

Document this function

Class Thread.Condition

Description

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:

  1. Take mutex lock

  2. Read/write shared resource

  3. Wait for the signal with the mutex lock in released state

  4. Reacquire mutex lock

  5. If needed, jump back to step 2 again

  6. Release mutex lock

Typical signal operation:

  1. Take mutex lock

  2. Read/write shared resource

  3. Send signal

  4. Release mutex lock

Example

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).

Note

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.

Note

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).

See also

Mutex


Method broadcast

void broadcast()

Description

broadcast() wakes up all threads currently waiting for this condition.

See also

signal()


Method create

Thread.Condition Thread.Condition(Thread.Mutex|void mutex)

Parameter mutex

Optional Mutex that protects the resource that the condition signals for.


Method signal

void signal()

Description

signal() wakes up one of the threads currently waiting for the condition.

Note

Sometimes more than one thread is woken up.

See also

broadcast()


Method wait

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)

Description

Wait for condition.

This function makes the current thread sleep until the condition variable is signalled or the timeout is reached.

Parameter 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.

Parameter seconds

Seconds to wait before the timeout is reached.

Parameter 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.

Note

The support for timeouts was added in Pike 7.8.121, which was after the first public release of Pike 7.8.

Note

Note that the timeout is approximate (best effort), and may be exceeded if eg the mutex is busy after the timeout.

Note

Note also that any threads waiting on the condition will be woken up when it gets destructed.

See also

Mutex->lock()

Class Thread.Farm

Description

A thread farm.

See also

8.0::Thread.Farm


Method debug_status

string debug_status()

Description

Get some statistics for the thread farm.


Method run

Concurrent.Future run(function(:void) f, mixed ... args)

Description

Register a job for the thread farm.

Parameter f

Function to call with @args to perform the job.

Parameter args

The parameters for f.

Returns

Returns a Result object for the job.

Note

In Pike 7.8 and earlier this function was broken and returned a Result object that wasn't connected to the job.

See also

run_async()


Method run_async

void run_async(function(:void) f, mixed ... args)

Description

Register a job for the thread farm where the return value from f is ignored.

Parameter f

Function to call with @args to perform the job.

Parameter args

The parameters for f.

See also

run()


Method run_multiple

Concurrent.Future run_multiple(array(array(function(:void)|array)) fun_args)

Description

Register multiple jobs.

Parameter 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

Returns a Concurrent.Future object with an array with one element for the result for each of the functions in fun_args.

Note

Do not modify the elements of fun_args before the result is available.

Note

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.

See also

run_multiple_async()


Method run_multiple_async

void run_multiple_async(array fun_args)

Description

Register multiple jobs where the return values are to be ignored.

Parameter fun_args

An array of arrays where the first element is a function to call, and the second is a corresponding array of arguments.

Note

Do not modify the elements of fun_args before the result is available.

See also

run_multiple()


Method set_max_num_threads

int set_max_num_threads(int(1..) to)

Description

Set the maximum number of worker threads that the thread farm may have.

Parameter 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.


Method set_thread_name_cb

void set_thread_name_cb(function(object, string:void) cb, void|string prefix)

Description

Provide a callback function to track names of threads created by the farm.

Parameter 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.

Parameter prefix

An optional name prefix to distinguish different farms. If not given a prefix will be generated automatically.

Class Thread.Farm.Handler

Description

A worker thread.


Method debug_status

string debug_status()

Description

Get some statistics about the worker thread.

Class Thread.Farm.ValueAdjuster


Variable r
Variable r2
Variable i
Variable v

object Thread.Farm.ValueAdjuster.r
object Thread.Farm.ValueAdjuster.r2
int Thread.Farm.ValueAdjuster.i
mapping Thread.Farm.ValueAdjuster.v


Method __create__

protected local void __create__(object r, object r2, int i, mapping v)


Method create

Thread.Farm.ValueAdjuster Thread.Farm.ValueAdjuster(object r, object r2, int i, mapping v)

Class Thread.Fifo

Description

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.

See also

Queue


Inherit lock

inherit Mutex : lock


Inherit r_cond

inherit Condition : r_cond


Inherit w_cond

inherit Condition : w_cond


Method create

Thread.Fifo Thread.Fifo()
Thread.Fifo Thread.Fifo(int size)

Description

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.


Method peek

mixed peek()

Description

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.

See also

read(), try_read()


Method read

mixed read()

Description

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.

See also

peek(), try_read(), read_array(), write()


Method read_array

array read_array()

Description

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.

See also

read(), try_read_array()


Method size

int size()

Description

This function returns the number of elements currently in the fifo.

See also

read(), write()


Method try_read

mixed try_read()

Description

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.

See also

peek(), read()


Method try_read_array

array try_read_array()

Description

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.

See also

read_array()


Method try_write

int try_write(mixed value)

Description

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.

See also

read()


Method write

int write(mixed value)

Description

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.

See also

read()

Class Thread.Local (< ValueType >)

Description

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.

Note

This class is simulated when Pike is compiled without thread support, so it's always available.


Generic ValueType

__generic__ mixed ValueType = mixed

Description

Type for the value to be stored in the thread local storage.


Method get

ValueType get()

Description

Get the thread local value.

This returns the value prevoiusly stored in the Local object by the set() method by this thread.

See also

set()


Method set

ValueType set(ValueType value)

Description

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).

Returns

This function returns its argument.

Note

Note that the value set can only be retreived by the same thread.

See also

get()

Class Thread.Mutex

Description

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.

Note

This class is simulated when Pike is compiled without thread support, so it's always available.

Note

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.


Method _sprintf

string sprintf(string format, ... Thread.Mutex arg ... )

Description

Describes the mutex including the thread that currently holds the lock (if any).


Method cond

Condition cond()

Description

Create a Condition.

This function is equivalent to

Thread.Condition(mux);
See also

Condition


Method current_locking_key

Thread.MutexKey current_locking_key()

Description

This mutex method returns the key object currently governing the lock on this mutex. 0 is returned if the mutex isn't locked.

See also

Thread()


Method current_locking_thread

Thread.Thread current_locking_thread()

Description

This mutex method returns the object that identifies the thread that has locked the mutex. 0 is returned if the mutex isn't locked.

See also

Thread()


Method future_lock

Concurrent.Future future_lock()

Description

This function is similar to lock(), but will return a Concurrent.Future(<Thread.MutexKey>) that will complete successfully when the Mutex is locked.

Note

Avoid having multiple future_lock's for different Mutexes pending concurrently in the same conceptual thread as this will likely cause dead-locks.


Method future_shared_lock

Concurrent.Future future_shared_lock()

Description

This function is similar to shared_lock(), but will return a Concurrent.Future(<Thread.MutexKey>) that will complete successfully when the Mutex is locked.

Note

Avoid having multiple future_shared_lock's for different Mutexes pending concurrently in the same conceptual thread as this will likely cause dead-locks.


Method lock

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)

Description

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:

0

Throw an error.

1

Sleep until the mutex is unlocked. Useful if some other thread will unlock it.

2

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.

Parameter seconds

Seconds to wait before the timeout is reached.

Parameter 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

Returns a MutexKey on success and 0 (zero) on timeout.

Note

The support for timeouts was added in Pike 8.1.14, which was before the first public release of Pike 8.1.

Note

Note that the timeout is approximate (best effort), and may be exceeded if eg the interpreter is busy after the timeout.

Note

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.

Note

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.

See also

trylock()


Method shared_lock

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)

Description

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:

0

Throw an error.

1

Sleep until the mutex is unlocked. Useful if some other thread will unlock it.

2

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.

Parameter seconds

Seconds to wait before the timeout is reached.

Parameter 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

Returns a MutexKey on success and 0 (zero) on timeout.

Note

Note that the timeout is approximate (best effort), and may be exceeded if eg the interpreter is busy after the timeout.

Note

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.

Note

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.

Note

Support for shared keys was added in Pike 8.1.

See also

lock(), trylock(), try_shared_lock()


Method try_shared_lock

MutexKey try_shared_lock()
MutexKey try_shared_lock(int type)

Description

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.

Note

Support for shared keys was added in Pike 8.1.

See also

shared_lock(), lock(), trylock()


Method trylock

MutexKey trylock()
MutexKey trylock(int type)

Description

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.

See also

lock()

Class Thread.MutexKey

Description

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).

See also

Mutex, Condition


Method _sprintf

string sprintf(string format, ... Thread.MutexKey arg ... )


Method downgrade

void downgrade()

Description

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().

See also

upgrade(), try_upgrade()


Method try_upgrade

bool try_upgrade()

Description

Try to upgrade a downgraded lock into an exclusive lock.

Returns
0

Returns 0 (zero) if there are other concurrent shared locks active.

1

Returns 1 if this is the only active lock, and upgrading it to being exclusive succeeded.

See also

downgrade(), upgrade()


Method upgrade

bool upgrade()
bool upgrade(int(0..)|float seconds)
bool upgrade(int(0..) seconds, int(0..999999999) nanos)

Description

Upgrade a downgraded lock into an exclusive lock.

Parameter seconds

Seconds to wait before the timeout is reached.

Parameter 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

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.

See also

downgrade(), try_upgrade()

Class Thread.Queue

Description

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.

FIXME

Ought to be made API-compatible with ADT.Queue.

See also

Fifo, ADT.Queue


Inherit lock

inherit Mutex : lock


Inherit r_cond

inherit Condition : r_cond


Method peek

mixed peek()

Description

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.

See also

peek(), read(), try_read(), write()


Method peek_array

array peek_array()

Description

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.


Method read

mixed read()

Description

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.

See also

peek(), try_read(), write()


Method read_array

array read_array()

Description

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.

See also

read(), try_read_array()


Method size

int size()

Description

This function returns the number of elements currently in the queue.

See also

read(), write()


Method try_read

mixed try_read()

Description

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.

See also

peek(), read(), write()


Method try_read_array

array try_read_array()

Description

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.

See also

read_array()


Method write

int write(mixed value)

Description

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.

See also

read()

Class Thread.ResourceCount

Description

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.

See also

ResourceCountKey, Condition, Mutex


Method acquire

final ResourceCountKey acquire()

Description

Increments the resource-counter.

Returns

A ResourceCountKey to decrement the resource-counter again.


Method drained

final bool drained(void|int level)

Parameter level

The maximum level that is considered drained.

Returns

True if the resource counter drops to equal or below level.


Method wait_till_drained

final void wait_till_drained(void|int level)

Description

Blocks until the resource-counter dips to max level.

Parameter level

The maximum level that is considered drained.

Class Thread.ResourceCountKey

Description

When this key is destroyed, the corresponding resource counter will be decremented.

See also

ResourceCount, MutexKey


Inherit DestructImmediate

private inherit __builtin.DestructImmediate : DestructImmediate

Class Thread.Thread


Method _sprintf

string sprintf(string format, ... Thread.Thread arg ... )

Description

Returns a string identifying the thread.


Method backtrace

array(mixed) backtrace(int|void flags)

Description

Returns the current call stack for the thread.

Parameter flags

A bit mask of flags affecting generation of the backtrace.

Currently a single flag is defined:

1

Return LiveBacktraceFrames. This flag causes the frame objects to track changes (as long as they are in use), and makes eg local variables for functions available for inspection or change.

Note that since these values are "live", they may change or dissapear at any time unless the corresponding thread has been halted or similar.

Returns

The result has the same format as for predef::backtrace().

See also

predef::backtrace()


Method create

Thread.Thread Thread.Thread(function(mixed ... :mixed|void) f, mixed ... args)

Description

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.

Returns

The returned value will be the same as the return value of this_thread() for the new thread.

Note

This function is only available on systems with POSIX or UNIX or WIN32 threads support.

See also

Mutex, Condition, this_thread()


Method gethrvtime

int gethrvtime(void|int nsec)

Returns

The CPU time consumed by this thread.

See also

predef::gethrvtime()


Method id_number

protected int id_number()

Description

Returns an id number identifying the thread.


Method interrupt

void interrupt()
void interrupt(string msg)

Description

Interrupt the thread with the message msg.

This function causes the thread to throw an error where the message defaults to "Interrupted.\n".

FIXME

The argument msg is currently ignored.

Note

Interrupts are asynchronous, and are currently not queued.

Note

Due to the asynchronous nature of interrupts, it may take some time before the thread reacts to the interrupt.


Method kill

void kill()

Description

Interrupt the thread, and terminate it.

Note

Interrupts are asynchronous, and are currently not queued.

Note

Due to the asynchronous nature of interrupts, it may take some time before the thread reacts to the interrupt.


Method status

int status()

Description

Returns the status of the thread.

Returns
Thread.THREAD_NOT_STARTED

The thread has not yet started executing.

Thread.THREAD_RUNNING

The thread has started and has not yet terminated.

Thread.THREAD_EXITED

The thread has terminated by returning a value from the thread function.

Thread.THREAD_ABORTED

The thread has terminated by throwing an uncaught error.


Method wait

mixed wait()

Description

Waits for the thread to complete, and then returns the value returned from the thread function.

Throws

Rethrows the error thrown by the thread if it exited by throwing an error.