JACK——PaintRobot Exercise11

来源:http://aosgrp.com/

 

Exercise 11

Use a semaphore to ensure that the robot only attempts to paint one part at a time.

 

Introduction

In Exercise 10, the main program only sent a new paint request to the robot when the previous part had been painted. This was because the submitPaintRequest methods invoked from the main Java thread used the postEventAndWait method. The submitPaintRequest method did not return until the part had received a reply to indicate that the paint process had been completed. If this was guaranteed to be the only way that paint requests were sent to the robot, no conflict would arise. However, if any other paint requests were sent from the JACK thread, the robot could attempt to paint more than one part at the same time.

An alternative technique to ensure that the robot only attempts to paint one part at a time is to use a semaphore. A semaphore is a synchronisation resource which can be used to establish mutual exclusion regions of processing in JACK plans and threads. A semaphore is a binary resource that plans and threads may wait for and signal on when they have completed. Waiting entities queue on the semaphore and acquire the semaphore in FIFO order.

The semaphore has a single constructor:

Semaphore()

Methods are provided to grab and release the semaphore. signal() is used to release the semaphore. The semaphore is grabbed initially by the constructing thread (or plan) and must thus be released by a call to signal(). To grab the semaphore from within a plan, use planWait(). The planWait() method returns a special JACK type, the Cursor.

The cursor concept originates from relational databases, where a query can return multiple tuples in the form of a result set. Access to the elements in this set is then provided through a cursor. In JACK, these concepts have been extended to provide cursors which not only operate in the conventional manner but also operate on the temporal evolution of a query. The latter type of cursor is typically used in JACK applications to determine when a particular condition becomes true. Cursors which provide this additional capability within JACK are implemented as triggered cursors. Triggered cursors are not checked using a busy-wait loop – rather, they are only tested when the agent performs a modification action that impacts on the cursor. The cursor returned by the planWait() method is triggered when the semaphore is grabbed by the plan.

This means that a plan can use the @waitFor reasoning statement to wait until the plan has been able to grab the semaphore before it begins painting the part.

In this exercise we introduce a new ProcessPaintRequest plan. This plan can only paint a part when it has the semaphore. If it does not have the semaphore, it must wait until it gets the semaphore before it paints the part.

 

Instructions

1. Create the named data of type Semaphore that is to be used to prevent the robot from attempting to paint more than one part at a time.

  • Open the Data Model container.
  • Right-click on the External Classes folder and select Add New External Class.
  • In the pop-up window that appears enter Semaphore as the name of the external class and enter aos.jack.util.thread as the package.
  • Click on the Add New button.
  • In the Agent Model container, right-click on the Named Data folder and select Add New Named Data from the menu.
  • In the pop-up window enter mutex as the name of the data and select aos.jack.util.thread.Semaphore as its type.
  • Click on the Add New button.

2. Open the Painting_DEP design diagram and

  •  Remove the sends links from the three 'painting' plans to the Finished event.
  • Drag a new plan from the design palette onto the Painting_DEP design diagram canvas. The new plan is called ProcessPaintRequest and is to be part of the robot package.
  • Create a new link from the ProcessPaintRequest event to the Finished event.
  • Drag a new event from the design palette onto the Painting_DEP design diagram canvas. The new event is to be called StartPainting and is to be part of the robot package.
  •  Remove the links between the Paint event and the three 'paint' plans.
  • Create a new link from the Paint event to the ProcessPaintRequest plan.
  • Create a posts event link from the ProcessPaintRequest plan to the StartPainting event.
  • Create handles links from the StartPainting event to each of the three 'painting' plans.
  • Drag the mutex named data onto the canvas.
  • Create a link from the ProcessPaintRequest plan to the mutex named data.
  • Drag the Painting capability onto the Painting_DEP design diagram.
  • Create the following links:

§ A uses link from the Painting capability to the ProcessPaintRequest plan.

§ A handles link from the StartPainting event to the Painting capability.

§ A posts link from the Painting capability to the StartPainting event.

§ A #private link from the Painting capability to the mutex data.

  •  Remove the Painting capability from the Painting_DEP design diagram. Your Painting_DEP should be similar to the following diagram:

clip_image001

Figure 13: The Painting_DEP design diagram with the ProcessPaintRequest plan, StartPainting event and mutex named data

3. Edit the StartPainting event so that it:

  • Extends BDIGoalEvent.
  • Has a String member colour and a String member from.
  • Has a posting method called startPainting:

startPainting(String c, String f)

{

colour = c;

from = f;

}

If editing the file as a JACK file, save and close the file before continuing.

4. As the semaphore is grabbed initially by the constructing thread, it must also be released by a call to signal(). The #private data Semaphore mutex(); declaration constructs the semaphore in the capability. Painting capability. To release the semaphore after it has been constructed, edit the capability and override its autorun method as follows:

protected void autorun()

{

mutex.signal();

}

5. Edit the ProcessPaintRequest plan as follows:

  • Edit the declarations at the beginning of the plan to use the following event references:

#handles event Paint pev;

#posts event StartPainting spev;

#sends event Finished fev;

  • Edit the body of the plan. This plan waits until it owns the semaphore before it subtasks the appropriate 'painting' plan to paint the part. When the 'painting' subtask is complete, the ProcessPaintRequest plan must send a Finished event back to the part. In addition, when the subtask is complete, this plan must release the semaphore. The body should therefore be as follows:

@waitFor(mutex.planWait()); // Wait for semaphore (mutex).

try {

@subtask(spev.startPainting(pev.colour, pev.from));

@send(pev.from, fev.finished(pev.colour));

}

finally {

mutex.signal(); // Release semaphore (mutex).

}

If editing the file as a JACK file, save and close the file before continuing.

6. Use the browser to remove the @reply statements from the three 'painting' plans.

7. Remove the @waitFor reply and associated statements from the Part agent's SendPaintCommand plan.

8. Open the PaintRequesting_DEP design diagram and

  • Drag a new plan from the design palette onto the PaintRequesting_DEP design diagram canvas. The new plan is to be called DisplayFinished and is to be part of the part package.
  • Create a handles link from the Finished event to the DisplayFinished plan.
  • Drag the PaintRequesting capability onto the PaintRequesting_DEP design diagram canvas.
  • Create the following links:

§ A uses link from the PaintRequesting capability to the DisplayFinished plan.

§ A handles link from the Finished event to the PaintRequesting capability.

  •  Remove the PaintRequesting capability from the PaintRequesting_DEP design diagram. Your PaintRequesting_DEP diagram should be similar to the following:

clip_image002

Figure 14: The PaintReqesting_DEP design diagram with the DisplayFinished plan and Finished event

9. Edit the DisplayFinished plan and

  • modify the #handles declaration to use fev as the reference to the Finished event handled by the plan.
  • Add a #uses interface Part self; declaration.
  • Add the details to the body of the plan. All that this plan needs to do is to display a message to indicate that the part has been painted a particular colour. It should contain a print statement similar to the following:

System.out.println(self.name()+" has been painted "

+fev.colour);

where fev is the reference to the Finished event handled by the plan.

If editing the file as a JACK file, save and close the file before continuing.

10. Save the project.

11. Compile and run the project.

 

示例程序

 

运行结果:

(1) test with red

(2) test with no specified colour

(3) Painting part1@%portal the new colour requested - red

(4) Painting part1@%portal the new colour requested - red 2nd coat

(5) test with green

(6) test with green

(7) No specified colour. Painting part2@%portal red

(8) part1@%portal received finished notification: colour red

(9) Painting part3@%portal the new colour requested - green

(10) Painting part3@%portal the new colour requested - green 2nd coat

(11) part2@%portal received finished notification: colour null

(12) Painting part4@%portal green

(13) part3@%portal received finished notification: colour green

(14) part4@%portal received finished notification: colour green

 

运行结果分析:

由于将Part Agent的SendCommandPlan中的waitFor移除,不再等待Robot Agent的reply,而Robot Agent中每个Plan中都会@sleep(5),所以应该会产生异步现象,即Robot Agent会同时处理多个Part Agent的绘制请求。

但从结果来看,虽然main线程不再同步,但是Robot Agent还是按照先来先处理的方式,处理完成后再处理下一个Part Agent的绘制请求。原因在于在Robot Agent使用信号semaphore,标识当前Robot Agent是否正在处理绘制请求进行控制,增添ProcessPaintRequest规划,在该规划中通过waitFor读取信号的状态,若当前信号占用,则一直等待,信号空闲,则通过planWait()获取该信号,开始处理当前的绘制请求,处理完成后通过signal()释放信号资源。

你可能感兴趣的:(paint)