Previous: , Up: Multitasker   [Contents][Index]

5.25.1 Ptheads

newtask       stacksize – task         unknown       “newtask”

creates a task, uses stacksize for stack, rstack, fpstack, locals

task       stacksize "name" –         SwiftForth       “task”

create a named task with stacksize stacksize

execute-task       xt – task         unknown       “execute-task”

create a new task task and initiate it with xt

stacksize       – n         unknown       “stacksize”

stacksize for data stack

newtask4       dsize rsize fsize lsize – task         unknown       “newtask4”

creates a task, each stack individually sized

stacksize4       – dsize fsize rsize lsize         unknown       “stacksize4”

This gives you the system stack sizes

activate       task –         unknown       “activate”

activates a task. The remaining part of the word calling activate will be executed in the context of the task.

pass       x1 .. xn n task –         unknown       “pass”

activates task, and passes n parameters from the data stack

initiate       xt task –         unknown       “initiate”

pass an xt to a task (VFX compatible)

pause              unknown       “pause”

voluntarily switch to the next waiting task (pause is the traditional cooperative task switcher; in the pthread multitasker, you don’t need pause for cooperation, but you still can use it e.g. when you have to resort to polling for some reason). This also checks for events in the queue.

restart       task –         unknown       “restart”

Wake a task

halt       task –         unknown       “halt”

Stop a task

stop              unknown       “stop”

stops the current task, and waits for events (which may restart it)

stop-ns       timeout –         unknown       “stop-ns”

Stop with timeout (in nanoseconds), better replacement for ms

UValue       "name" –         unknown       “UValue”

Define a per-thread value

UDefer       "name" –         unknown       “UDefer”

Define a per-thread deferred word

user'       ’user’ – n         unknown       “user”’

USER’ computes the task offset of a user variable

A cooperative multitasker can ensure that there is no other task interacting between two invocations of pause. Pthreads however are really concurrent tasks (at least on a multi-core CPU), and therefore, several techniques to avoid conflicts when accessing the same resources. Semaphores

Semaphores can only be aquired by one thread, all other threads have to wait until the semapohre is released.

semaphore       "name" –         gforth       “semaphore”

create a named semaphore "name" \\ "name"-execution: ( – semaphore )

lock       semaphore –         unknown       “lock”

lock the semaphore

unlock       semaphore –         unknown       “unlock”

unlock the semaphore

The other approach to prevent concurrent access is the critical section. Here, we implement a critical section with a semaphore, so you have to specify the semaphore which is used for the critical section. Only those critical sections which use the same semaphore are mutually exclusive.

critical-section       xt semaphore –         unknown       “critical-section”

implement a critical section that will unlock the semaphore even in case there’s an exception within. Atomic operations

Experimental atomic operations

!@       u1 a-addr – u2        gforth       “store-fetch”

load u2< from a_addr<, and store u1< there, as atomic operation

+!@       u1 a-addr – u2        gforth       “add-store-fetch”

load u2< from a_addr<, and increment this location by u1<, as atomic operation

?!@       unew uold a-addr – uprev        gforth       “question-store-fetch”

load uprev< from a_addr<, compare it to uold<, and if equal, store unew< there, as atomic operation

barrier              gforth       “barrier”

Insert a memory barrier Message Queues

Gforth implements executable message queues for event driven programs: you send instructions to other tasks, enclosed in <event and event>; the entire event sequence is executed atomically. You can pass integers, floats, and strings (only the addresses, so treat the string as read-only after you have send it to another task). The messages you send are defined with event: name, which, when invoked, will add the code for its execution to the message queue, and when recieved, will execute the code following. The message queue is queried when you stop a task, or when you check for events with ?events. You can define a maximum of 256 different events.

<event              unknown       “<event”

starts a sequence of events.

event>       task –         unknown       “event>”

ends a sequence and sends it to the mentioned task

event:       "name" –         unknown       “event:”

defines an event and the reaction to it as Forth code. If name is invoked, the event gets assembled to the event buffer. If the event name is received, the Forth definition that follows the event declaration is executed.

?events              unknown       “?events”

checks for events and executes them

event-loop              unknown       “event-loop”

Tasks that are controlled by sending events to them should go into an event-loop

elit,       x –         unknown       “elit,”

sends a literal

e$,       addr u –         unknown       “e$,”

sends a string (actually only the address and the count, because it’s shared memory

eflit,       x –         unknown       “eflit,”

sends a float

The naming conventions for events is :>name. Conditions

The pthreads library also provides conditional variables, which allow to wait for a condition. Using the message queue is generally preferred.

cond       "name" –         gforth       “cond”

create a named condition

pthread_cond_signal       unknown         unknown       “pthread_cond_signal”
pthread_cond_broadcast       unknown         unknown       “pthread_cond_broadcast”
pthread_cond_wait       unknown         unknown       “pthread_cond_wait”
pthread_cond_timedwait       unknown         unknown       “pthread_cond_timedwait”

Previous: , Up: Multitasker   [Contents][Index]