149 lines
3.5 KiB
Text
149 lines
3.5 KiB
Text
|
CLASS::Semaphore
|
||
|
categories::Scheduling
|
||
|
summary::control parallel execution of threads
|
||
|
|
||
|
CLASSMETHODS::
|
||
|
|
||
|
method::new
|
||
|
Create a new instance, set the maximum number of running threads (default: 1).
|
||
|
|
||
|
INSTANCEMETHODS::
|
||
|
|
||
|
method::count
|
||
|
Determines the number of running threads.
|
||
|
|
||
|
method::clear
|
||
|
Remove any reference to threads, but do not reschedule any pending ones.
|
||
|
|
||
|
method::wait
|
||
|
Stop current thread if already too many are running, otherwise continue.
|
||
|
|
||
|
method::signal
|
||
|
Unblock the semaphore, reschedule next pending thread.
|
||
|
|
||
|
EXAMPLES::
|
||
|
|
||
|
code::
|
||
|
// allow only one thread
|
||
|
(
|
||
|
c = Semaphore(1);
|
||
|
fork {
|
||
|
c.wait;
|
||
|
"thread 1> now I am doing something for 10 seconds. Block the semaphore meanwhile.".postln;
|
||
|
10.wait;
|
||
|
c.signal;
|
||
|
"thread 1> ok, done. Release the semaphore.".postln;
|
||
|
};
|
||
|
fork {
|
||
|
3.0.rand.wait;
|
||
|
"thread 2> I would like to go on, if I may.".postln;
|
||
|
c.wait; // may I?
|
||
|
"thread 2> this took until the other thread has released the semaphore. "
|
||
|
"Blocking for 4 seconds.".postln;
|
||
|
4.wait;
|
||
|
"thread 2> ok, done. Releasing the semaphore".postln;
|
||
|
c.signal;
|
||
|
};
|
||
|
fork {
|
||
|
4.wait;
|
||
|
"thread 3> I, too, would like to go on, if I may.".postln;
|
||
|
c.wait; // may I?
|
||
|
"thread 3> this took until both other threads had released the semaphore.".postln;
|
||
|
c.signal;
|
||
|
};
|
||
|
)
|
||
|
::
|
||
|
|
||
|
code::
|
||
|
// allow two threads at a time.
|
||
|
(
|
||
|
c = Semaphore(2);
|
||
|
fork {
|
||
|
c.wait;
|
||
|
"thread 1> now I am doing something for 20 seconds. Block the semaphore.".postln;
|
||
|
10.wait;
|
||
|
"thread 1> ok, done. Releasing the semaphore".postln;
|
||
|
c.signal;
|
||
|
};
|
||
|
fork {
|
||
|
rrand(3.0, 5.0).wait;
|
||
|
"thread 2> I would like to go on, if I may.".postln;
|
||
|
if(c.count <= 0) { "thread 3> ok, then I wait ...".postln };
|
||
|
c.wait; // may I?
|
||
|
"thread 1> ok, going ahead.".postln;
|
||
|
17.wait;
|
||
|
"thread 2> ok, done. Releasing the semaphore".postln;
|
||
|
c.signal;
|
||
|
};
|
||
|
fork {
|
||
|
6.wait;
|
||
|
"thread 3> I, too, would like to go on, if I may.".postln;
|
||
|
if(c.count <= 0) { "thread 3> ok, then I wait ...".postln };
|
||
|
c.wait; // may I?
|
||
|
"thread 3> ok, this took until the first thread had released the semaphore. "
|
||
|
"Ok, doing something for 4 seconds. Block the semaphore".postln;
|
||
|
4.wait;
|
||
|
"Releasing the semaphore.".postln;
|
||
|
c.signal;
|
||
|
};
|
||
|
fork {
|
||
|
7.wait;
|
||
|
"thread 4> Me, the fourth one, would like to go on, if I may.".postln;
|
||
|
if(c.count <= 0) { "thread 4> ok, then I wait ...".postln };
|
||
|
c.wait; // may I?
|
||
|
"thread 4> ok, this took until the third thread had released the semaphore. "
|
||
|
"Ok, doing something for 3 seconds. Block the semaphore".postln;
|
||
|
3.wait;
|
||
|
"Releasing the semaphore.".postln;
|
||
|
c.signal;
|
||
|
};
|
||
|
)
|
||
|
::
|
||
|
|
||
|
code::
|
||
|
// grant exclusive access to data to only one thread
|
||
|
// there should never be mixed values in the data array
|
||
|
(
|
||
|
var data, useAndModify;
|
||
|
|
||
|
data = [1, 2, 3];
|
||
|
c = Semaphore(1);
|
||
|
// c = Semaphore(2); use this to test how it would behave without exclusive access.
|
||
|
useAndModify = { |newData, who|
|
||
|
postln(who + "trying to get blocking access.");
|
||
|
if(c.count <= 0) { who + "ok, then I wait ...".postln };
|
||
|
c.wait; // may I access? if not, I wait. if yes, disallow others.
|
||
|
"\n".post;
|
||
|
(who + "continuing...").postln;
|
||
|
data.do({ |x|
|
||
|
0.1.wait;
|
||
|
postln(who + x);
|
||
|
});
|
||
|
"\n".post;
|
||
|
newData.do { |x, i| data[i] = x };
|
||
|
postln(who + "rewriting data to:" + newData);
|
||
|
postln(who + "releasing");
|
||
|
c.signal; // allow others access again
|
||
|
};
|
||
|
|
||
|
// e.g. set the values to integers
|
||
|
u = Routine {
|
||
|
inf.do { |i|
|
||
|
useAndModify.value([100, 200, 300], "thread 1>");
|
||
|
rrand(1, 3).wait;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// e.g. set the values to floats
|
||
|
k = Routine {
|
||
|
0.5.wait;
|
||
|
inf.do { |i|
|
||
|
useAndModify.value([pi, 0.5pi, 2pi], "thread 2>");
|
||
|
rrand(1, 5).wait;
|
||
|
}
|
||
|
};
|
||
|
u.play;
|
||
|
k.play;
|
||
|
);
|
||
|
::
|