Exercise 5: Working with Agents

Figure 1

In this exercise you will work with a code that will show you how agents communicate with one another. We’ll make use of an unbounded buffer and an overwrite buffer to have a couple of agents communicate with one another. The diagram below shows what will be accomplished:

Figure 2

In this illustration, agent1 sends a message to agent2 by using the send function and an unbounded_buffer object. agent2 uses the receive function to read the message. agent2 uses the same method to send a message to agent1. Dashed arrows represent the flow of data from one agent to the other. Solid arrows connect each agent to the message blocks that they write to or read from.

Part 1: Create the Buffers

  1. Open the Exercise-5 solution file found at the following folder:

    C:\Server 2008 R2 Labs\Working with the CRT\Exercise-5\

  2. From the Solution Explorer, double click the Exercise-5.cpp file under the Sources folder.
  3. Scroll down to the main function to make all the required changes.
  4. If you recall from our diagram, agent1 will send a value to agent2 via an unbounded buffer. To declare this buffer, write the following line right below the // Declare the unbounded buffer below comment:

    C++

    unbounded_buffer<string> buffer1;
    Note:
    An Unbounded_buffer is one of the most basic messaging blocks; it acts very similar to a queue. As its name suggests unbounded_buffer can store any number of messages, limited only by memory, collected from its source links (links to blocks that have the unbounded_buffer as a target).

  5. On the other hand, agent2 will send a single value to agent1 (an int). In order to set the overwrite buffer, write the following line below the // Declare the overwrite buffer below comment:

C++

overwrite_buffer<int> buffer2;

Part 2: Create and Start the Agents

  1. While still in main, we need to create the agents that will be used. Write down the following lines below the // Step 2: Create the agents comment:

    C++

    agent1 first_agent(buffer2, buffer1); agent2 second_agent(buffer1, buffer2);
    Note:
    Soon enough you will see the constructor signatures of the agents, but for the time being remember that agent1 will send out buffer1 to agent2 and will receive the message sent by agent2 in buffer2.

    We’ve included the diagram again to make it clearer:

    Figure 3

  2. In order to start the agents and have them execute in parallel, type the lines below right after the // Step 3: Start the agents. The runtime calls the run method on each agent comment:

    C++

    first_agent.start(); second_agent.start();

  3. Next, we need to wait for both agents to finish, which can be done by invoking the wait method. Type the following lines right below the // Step 4: Wait for both agents to finish comment:

    C++

    agent::wait(&first_agent); agent::wait(&second_agent);

Part 3: Implement agent1

  1. Scroll all the way to the top of the file. You will see the declaration of agent1, which inherits from the agent class:

    C++

    class agent1 : public agent

  2. Further down, you will see the constructor for the agent class:

    C++

    public: explicit agent1(ISource<int>& source, ITarget<string>& target) : _source(source) , _target(target)
    Note:
    The ISource class is the interface for all Source blocks. Source blocks have messages to pass to Target blocks. The ITarget class is the interface for all Target blocks. Target blocks consume messages passed down by ISources.

    Also notice that the constructor is using an r-value reference in its parameter list (the &). This is a new language construct in Visual Studio 2010 that is part of the draft C++0x standard. An r-value reference here allows the compiler to avoid a copy constructor call and move source and target into _source and _target, respectively.

  3. Scroll down until you see the run method. The first thing we want to do is send the target parameter agent2. To do this, write the following line below the // Send the request comment:

    C++

    printf("agent1: Sending Request\n"); send(_target, string("request"));

  4. Next, we know that agent2 is going to send us a value back, so we tell the agent to read the response by typing this line below the // Read the response comment:

    C++

    int response = receive(_source);
  5. printf("agent1: received '%d'.\n", response);
  6. Next, we must signal that the agent has finished by calling the done method, which needs to be typed right after the // Signal Completion comment:

    C++

    done();

Part 4: Implement agent2

  1. Scroll down to the agent2 class. Take a minute to examine the class, you should notice some similarities with the agent1 class.
  2. Navigate to the run method of the agent2 class.
  3. The first thing we must do is receive the message that was sent by agent1. To do so, type the following lines below the // Read the request comment:

    C++

    string request = receive(_source); printf("agent2: received '%s'.\n", request.c_str());

  4. Next, we’ll send a message to agent1 via the overwrite buffer. In this case, we’ll send the value of 42. Write down the following line below the //Send the response comment:

    C++

    printf("agent2: sending response...\n"); send(_target, 42);

  5. Next, we must signal that the agent has finished by calling the done method, which needs to be typed right after the // Signal Completion comment:

    C++

    done();

  6. From the Debug menu, select Build Rebuild Solution
Note:
Your build should succeed. If you encounter any errors, please backtrack your steps and double-check each instruction.

Part 5: Test the Program

  1. From the Debug menu, select Start without Debugging
  2. Your output should be similar to the one show below:

    Figure 4

Note:
As you can see from the output, agent1 starts up and sends the request to agent2, which was already started and waiting for the request from agent1. Once agent2 received the request, it sent the response (42) to agent1. At this point, agent2 had signaled that it was done and agent1 received the number. Shortly after, agent1 also signaled that it was done and the program finished executing.