INTERCAL-72 | C-INTERCAL | CLC-INTERCAL | J-INTERCAL |
---|---|---|---|
no | version 0.25+ | version 0.05+ | no |
The original multithreading implementation worked by giving a new
meaning to what was previously an error condition. If in a
multithreaded program (a program is marked as multithreaded using
options to a compiler) two or more COME FROM
s or
NEXT FROM
s (or a mixture of these) attempt to steal
control simultaneously, the original thread splits into multiple
threads, one for each of the commands trying to take control, and a
different command gains control of the program in each case.
From then on, all the threads run simultaneously. The only thing shared
between threads (apart from the environment in which they run) is the
abstained/reinstated status of each command; everything else is
separate. This means, for instance, that it’s possible to change
the value of a variable in one thread, and it will not affect the
corresponding variable in other threads created this way. Likewise,
there is a separate NEXT stack in each thread; if both a COME
FROM
and a NEXT FROM
aim at the same line, for
instance, the NEXT FROM
thread will end up with a NEXT
stack entry that isn’t in the COME FROM
thread,
created by the NEXT FROM
itself. This is known as unwoven
thread creation; none of the threads created this way are
‘woven’ with any of the other threads created this way.
(Whether threads are woven depends on how they were created.) If the
thread being split was itself woven with other threads, exactly one of
the resulting threads after the split is woven with the threads that
the original thread was woven to, but the rest will not be woven to
anything. (If that seems a somewhat unusual rule: well, this is
INTERCAL.)
In C-INTERCAL, there are other guarantees that can be made
about unwoven threads (that is, threads not woven to any other thread).
In particular, they can all be guaranteed to run at approximately the
same speed; to be more precise, the number of commands that have been
given the chance to execute in any given thread will not differ by more
than 2 from the number of commands that have been given the chance to
execute in any other thread that was created at the same time.
(However, COME FROM
s and NEXT FROM
s can make
this relationship less precise; it is unspecified (in the technical
sense that means the compiler can choose any option it likes and change
its mind on a whim without telling anyone) whether a COME
FROM
or NEXT FROM
aiming at the current command
counts towards the command total or not, thus causing the relationship
to become weaker the more of them have the chance to execute. In
versions of C-INTERCAL from 0.27 onwards, there is a third
guarantee; that if a COME FROM
comes from itself, it will
actually give other threads at least some chance to run, at some speed,
by counting itself as a command every now and then; previously this
requirement didn’t exist, meaning that a COME FROM
could block all threads if it aimed for itself due to the speed
restrictions and the fact that COME FROM
s need not count
towards the total command count.) Also, all commands, including any
ONCE
or AGAIN
attached to the command, are
atomic; this means that it’s impossible for another thread to
conflict with what the command is doing. (In a departure from the usual
INTERCAL status quo, these guarantees are somewhat
better than in most other languages that implement threading,
amusingly continuing to leave INTERCAL with the
status of being unlike any other mainstream language.)
The only way to communicate between unwoven threads is by changing the
abstention status of commands; this always affects all threads in the
program, whether woven or not. (The combination of ABSTAIN
and ONCE
is one way to communicate atomically, due to the
atomic nature of ONCE
.)
If there are at least two threads, the GIVE UP
command
ends the current thread, rather than the current program.