I'm trying to use an agent callback concurrently. Unfortunately, no matter what I do it always seems to run sequentially instead of parallel. (without the agent it doesn't)
main class(APPLICATION):
class
APPLICATION
inherit
ARGUMENTS
create
make
feature {NONE} -- Initialization
make
-- Run application.
local
a1 : separate PROCEDURE
a2 : separate PROCEDURE
do
create my_counter.make (1, 100_000_000)
create my_counter2.make (2, 100_000_000)
launch_counter(my_counter)
launch_counter(my_counter2)
end
feature -- Launch
launch_counter(c: separate COUNTER)
do
c.run (5, agent print_hello)
end
print_hello
do
print("Hello!%N")
end
feature -- Access
my_counter : separate COUNTER
my_counter2 : separate COUNTER
end
counter class:
class
COUNTER
inherit
EXECUTION_ENVIRONMENT
create
make
feature -- Initilzation
make (i: INTEGER; delay: INTEGER)
do
id := i
delay_time := delay
end
feature -- Stuff
run (times: INTEGER; p: separate PROCEDURE)
local
c : INTEGER
do
from
c := times
until
c = 0
loop
print("COUNTER: " + id.out)
p.call
sleep(delay_time)
c := c - 1
end
end
feature {NONE} -- Access
delay_time : INTEGER
id: INTEGER
end
expected output:
COUNTER: 1Hello!
COUNTER: 2Hello!
COUNTER: 1Hello!
etc.
actual output:
COUNTER: 1Hello!
COUNTER: 1Hello!
COUNTER: 1Hello!
COUNTER: 1Hello!
COUNTER: 1Hello!
COUNTER: 2Hello!
COUNTER: 2Hello!
COUNTER: 2Hello!
COUNTER: 2Hello!
COUNTER: 2Hello!
What would I have to change to make this run as expected?
The agent object keeps a reference to the target, in your example to the root object of type APPLICAITON
, therefore all calls to print_hello
get synchronized. To avoid that, the objects on which the agent is called should be recorded in a COUNTER
object and used from there.
This can be achieved by adding an attribute action
to the class COUNTER
and updating its creation procedure
make (i: INTEGER; delay: INTEGER; a: separate PROCEDURE)
do
id := i
delay_time := delay
action := a
end
...
action: separate PROCEDURE
Then instead of p.call
in COUNTER.run
the following code will be used (the feature run
has no argument p
anymore):
separate action as p do
p.call
end
Now p
is not locked on entry to the feature run
and therefore callbacks can be executed alternately by different processors.