Going Up?
by Sam Tregar
|
Pages: 1, 2, 3, 4
Building State
The building is represented in the simulation with three shared
variables, %DOOR, @BUTTON and %PANEL. These variables are
declared as shared using the shared attribute:
# Building State
our %DOOR : shared; # a door for each elevator on each floor
our @BUTTON : shared; # a button for each floor to call the elevators
our %PANEL : shared; # a panel of buttons in each elevator for each floor
When a variable is marked as shared its state will be synchronized between threads. If one thread makes a change to a shared variable then all the other threads will see that change. This means that threads will need to lock the variable in order to access it safely, as I'll demonstrate below.
The building state is initialized in the init_building() function.
# initialize building state
sub init_building {
# set all indicators to 0 to start the simulation
for my $floor (0 .. $NUM_FLOORS - 1) {
$BUTTON[$floor] = 0;
for my $elevator (0 .. $NUM_ELEVATORS - 1) {
$PANEL{"$elevator.$floor"} = 0;
$DOOR{"$elevator.$floor"} = 0;
}
}
}
The buttons on each floor are set to 0 to indicate that they are
``off.'' When a person wants to summon the elevator to a floor they
will set the button for that floor to 1 ($BUTTON[$floor] = 1).For
each elevator there are a set of panel buttons and a set of doors, one
for each floor. These are all cleared to 0 at the start of the
simulation. When an elevator reaches a floor it will open the door by
setting the appropriate item in %DOOR to 1
($DOOR{"$elevator.$floor"} = 1). Similarly, people tell the
elevators where to go by setting entries in %PANEL to 1
($PANEL{"$elevator.$floor"} = 1).
Figure 2 shows a single-elevator building with four floors and three people. Don't worry if this doesn't make much sense yet, you'll see it in action later.
Thread Creation
After calling init_building() to initialize the shared building
state variables, the program creates the elevator threads inside
init_elevator():
# create elevator threads
sub init_elevator {
our @elevators;
for (0 .. $NUM_ELEVATORS - 1) {
# pass each elevator thread a unique elevator id
push @elevators, threads->new(\&Elevator::run,
id => $_);
}
}
Threads are created by calling threads->new(). The first
argument to threads->new() is a subroutine reference where the
new thread will begin execution. In this case, it is the
Elevator::run() subroutine declared later in the program. Anything
after the first argument is passed as an argument to this subroutine.
In this case each elevator is given a unique ID starting at 0.
The return value from threads->new() is an object representing
the created thread. This is saved in a global variable,
@elevators, for use later in shutting down the simulation.
After the elevators are created the simulation is ready to send in
people with the init_people() routine:
# create people threads
sub init_people {
our @people;
for (0 .. $NUM_PEOPLE - 1) {
# pass each person thread a unique person id and a random
# destination
push @people, threads->new(\&Person::run,
id => $_,
dest => int(rand($NUM_FLOORS - 2)) + 1);
# pause if we've launched enough people this second
sleep 1 unless $_ % $PEOPLE_FREQ;
}
}
This routine creates $PEOPLE_FREQ people and then sleeps for one
second before continuing. If this wasn't done, then all the people would
arrive at the building at the same time and the simulation would be
rather boring. Notice that while the main thread sleeps the
simulation is proceeding in the elevator and people threads.
The people threads start at Person::run(), which will be described
later. Person::run() receives two parameters - a unique ID and a
randomly chosen destination floor. Each person will board an elevator
at the ground floor, ride to this floor, wait there for a set period
of time and then ride an elevator back down.

