Following difference from by turns programming is that there are general data for the big number of processes. And in some cases it is required to get individual access up to these data.
>('x set 0) 0 >(100 for i ('x set (x + 1))) ; there will be 100 parallel processes nil >x 7
The given possibility can be received using locks:
>('x set 0) 0 >('xlock set ('lock newobject)) Lock >(100 for i (xlock progn ('x set (x + 1)))) nil >x 100
The most important that all processes which are changed by the general data, used the lock. The matter is that the lock it simply tag - a sign on that the place is borrowed. And if to not pay attention to tags it is possible to make all everything.
Signals are necessary for dialogue of several processes. If process expects execution of some task performance of cyclic check very strongly and as much as possible loads processors with useless work.
At program compilation the lock at first is put. Under lock protection it is checked there is a necessity to use signals. Then very simple function wait is used. This function opens the lock and the signal from other processes waits. After reception of a signal the lock is again installed.
At by turns (without parallelism) program programming permanently check some conditions. It complicates programming and is very strongly subject to errors. At usage of signals the program turns out is very simple and effective.
Let's bring very simple example:
('signal set ('signal newobject)) ('lock set ('lock newobject)) ('s set (10 copy)) (nil parallel ; main task (lock progn (cout writeln "waiting...") (signal wait lock) (cout writeln "OK")) ; another task (nil progn (nil while (s > 0) (lock progn (cout writeln "work") (s -= 1))) (cout writeln "send signal") (signal send)))
The order of giving, expectation of a signal has no value. The sent signals do not vanish.
In large projects sometimes there is a necessity to handle the big source of the information, not updating it. Also it is desirable to give the chance to parallel processes will be fulfilled simultaneously. If there was a necessity to update information that is necessary that one process worked.
This fantastic process can be made efforts of locks and signals. Let's make a class passage which will organise all process of operation.
(('passage defclass) defvar lockEntrance lockOutlet signalShout guests flagToShout) ('passage defmethod passage () (nil setq lockEntrance ('lock newobject) lockOutlet ('lock newobject) signalShout ('signal newobject) guests (0 copy) flagToShout false)) ('passage defmacro Pass (env &rest body) (lockEntrance progn (lockOutlet progn (guests += 1))) (nil let ((result (env eval `(nil progn ,@body)))) (lockOutlet progn (nil if ((guests -= 1) = 0) (nil when flagToShout ('flagToShout set false) (signalShout send)))) `',result)) ('passage defmacro Lock (env &rest body) (lockEntrance progn (lockOutlet progn (nil when (guests <> 0) ('flagToShout set true) (signalShout wait lockOutlet))) `',(env eval `(nil progn ,@body))))