Skip to content

Commit

Permalink
[core][sre][docs] Add the atFixedDelay() function in the Schedules ca…
Browse files Browse the repository at this point in the history
…pacity.

see #243

Signed-off-by: Stéphane Galland <galland@arakhne.org>
  • Loading branch information
gallandarakhneorg committed Nov 21, 2016
1 parent 52a0b77 commit b4cf839
Show file tree
Hide file tree
Showing 8 changed files with 835 additions and 226 deletions.
Expand Up @@ -1084,7 +1084,7 @@ describe "Built-in Capacity Reference" {
}".parseSuccessfully
}

/* For running a periodic task, the following functions are
/* For running a periodic task with a fixed starting rate, the following functions are
* provided:
*
* def every(period : long,
Expand Down Expand Up @@ -1130,7 +1130,7 @@ describe "Built-in Capacity Reference" {
*
* @filter(.*)
*/
fact "Launching a Periodic Task"{
fact "Launching a Periodic Task at a Fixed Rate"{
"GeneralSyntaxReferenceSpec.html" should beAccessibleFrom this
//
" package io.sarl.docs.reference.bic
Expand All @@ -1153,6 +1153,73 @@ describe "Built-in Capacity Reference" {
}".parseSuccessfully
}

/* For running a periodic task with a fixed duration between the runs, the following functions are
* provided:
*
* def atFixedDelay(period : long,
* procedure : (Agent) => void) : AgentTask
* def atFixedDelay(period : AgentTask,
* delay : long,
* procedure : (Agent) => void) : AgentTask
*
*
* <p>The first function submits the given procedure (a lambda expression as defined in
* the [General Syntax Reference](GeneralSyntaxReferenceSpec.html)) to
* an executor provided by the runtime platform. The execution of the procedure
* will be launched periodically with a duration between the runs of the given number of milliseconds.
* This function replies the agent task for controlling its execution.
*
* <p>The second function behaves in a similar way as the first, except that it
* accepts an agent task as parameter. This task will attach to the given
* procedure. The replied task is the same as the task given as parameter.
*
* <p>The `atFixedDelay` function has not the same issue ass the `every` function
* regarding the possibility to have several runs in parallel.
* The `atFixedDelay` ensures that only one run of the procedure will be executed at a giveen time.
*
* <p>For example, the following code may be illustrated by the table below.
*
*
* atFixedDelay(500) [ sleep(2000) ]
*
*
*
* <table>
* <thead>
* <tr><th>t=</th><th>0</th><th>500</th><th>1000</th><th>1500</th><th>2000</th><th>2500</th><th>3000</th><th>3500</th><th>4000</th><th>4500</th><t5>5000</th><th>5500</th><th>6000</th><th>6500</th></tr>
* </thead>
* <tbody>
* <tr><td>A</td><td>X</td><td>X</td><td>X</td><td>X</td><td></td><td></td><td></td><td></td><td></td></tr><td></td><td></td><td></td><td></td><td></td>
* <tr><td>B</td><td></td><td></td><td></td><td></td><td></td><td>X</td><td>X</td><td>X</td><td>X</td><td></td><td></td><td></td><td></td><td></td></tr>
* <tr><td>C</td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td>X</td><td>X</td><td>X</td><td>X</td></tr>
* </tbody>
* </table>
*
* @filter(.*)
*/
fact "Launching a Periodic Task with a Fixed Delay between the Runs"{
"GeneralSyntaxReferenceSpec.html" should beAccessibleFrom this
//
" package io.sarl.docs.reference.bic
import io.sarl.core.Logging
import io.sarl.core.Schedules
import io.sarl.core.AgentTask
import io.sarl.lang.core.Agent
agent A {
uses Schedules, Logging
def myaction {
var t1 : AgentTask
var t2 : AgentTask
t1 = atFixedDelay(1000) [ a : Agent |
println(a)
]
t1 = t2.atFixedDelay(1000) [ a : Agent |
println(a)
]
}
}".parseSuccessfully
}

/* It may be useful to cancel a running task, e.g. a
* periodic task. The `Schedules` capacity
* provides two functions for stopping the execution
Expand Down
Expand Up @@ -2192,6 +2192,9 @@ describe "Creating a SARL Run-time Environment for the tinyMAS platform"{
* the `in` function, except that the `period` field of the `Task` is set
* with the period duration, which is given as parameter.
*
* <p>The `atFixedDelay` function delegates to the `every` function because the task running
* algorithm implies that these two types of execution approach will be the same on tinyMAS.
*
* @filter(.* = '''|'''|.parseSuccessfully.*)
*/
fact "Scheduling a periodic agent task" {
Expand All @@ -2210,6 +2213,10 @@ describe "Creating a SARL Run-time Environment for the tinyMAS platform"{
scheduleTask(time, theTask)
return theTask
}
def atFixedDelay(task : AgentTask = null, delay : long, procedure : (io.sarl.lang.core.Agent) => void) : AgentTask {
return task.every(delay, procedure)
}
'''.parseSuccessfully(
'''
package io.sarl.docs.tutorials.tinyMASSRE
Expand Down
44 changes: 41 additions & 3 deletions eclipse-sarl/plugins/io.sarl.core/src/io/sarl/core/bic.sarl
Expand Up @@ -353,9 +353,10 @@ capacity Schedules {

/**
* Schedule a periodic execution of the given task.
* <p>
* If the duration of the task is greater to the given period length, then
* multiple task's instances will be run in parallel.
*
* <p>If the duration of the task is greater to the given period length, then
* multiple task's instances will be run in parallel, in opposite to the
* {@code atFixedDelay()} function.
* For example, consider the following code:
* <pre><code>
* every(500) [ sleep(2000) ]
Expand All @@ -371,6 +372,8 @@ capacity Schedules {
* [-E-------------------------]
* [-F-------------------------]
* </code></pre>
* For executing a task with a fixed delay between the runs, and not at a fixed rate,
* you should use the {@code atFixedDelay()} function.
*
* <p>The given procedure takes one parameter: the agent associated to the task. It is name <code>it</code> by default.
*
Expand All @@ -381,6 +384,41 @@ capacity Schedules {
*/
def every(task : AgentTask = null, period : long, procedure : (Agent) => void ) : AgentTask

/**
* Schedule a single-execution task.
*
* <p>If the duration of the task is greater to the given delay length, then
* no multiple task's instance are run in parallel, in opposite to the
* {@code every()} function.
* For example, consider the following code:
* <pre><code>
* atFixedDelay(500) [ sleep(2000) ]
* </code></pre>
* At a given time, 3 instances (A, B, C) of the task are run in sequence, and
* each run is separated by 500 milliseconds:
* <pre><code>
* t=0 0500 1000 1500 2000 2500 3000 3500 4000 4500 5000
* | | | | | | | | | | |
* [-A-----------------------]
* [-B-------------------------]
* [-C-------------------------]
* </code></pre>
* For executing a task with a fixed rate, and not with a fixed delay between the task runs,
* you should use the {@code every()} function.
*
* <p>The given procedure takes one parameter: the agent associated to the task. It is name <code>it</code> by default.
*
* <p>It is recommended that the SRAL run-time environment, which is providing the implementation
* of this function to provide an efficient implementation in the case the argument
* {@code delay} is equal to zero. Indeed, if the {@code delay} is equal to zero, the task
* should be run in an infinite loop until it is canceled, or the owning agent is killed.
*
* @param task the task to associate to the procedure. If <code>null</code> a new task is created.
* @param procedure the procedure to launch. The parameter of the procedure is the agent.
* @return the given task.
* @since 0.5
*/
def atFixedDelay(task : AgentTask = null, delay : long, procedure : (Agent) => void ) : AgentTask
}


Expand Down
Expand Up @@ -42,6 +42,7 @@ public class Messages extends NLS {
public static String SchedulesSkill_0;
public static String SchedulesSkill_1;
public static String SchedulesSkill_2;
public static String SchedulesSkill_3;
static {
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, Messages.class);
Expand Down

0 comments on commit b4cf839

Please sign in to comment.