Author:halw

Date:2011-02-08T22:13:37.000000Z


git-svn-id: https://svn.eiffel.com/eiffel-org/trunk@754 abb3cda0-5349-4a8f-a601-0c33ac3a8c38
This commit is contained in:
halw
2011-02-08 22:13:37 +00:00
parent ba4e141811
commit 541bf3ce57
2 changed files with 45 additions and 7 deletions

View File

@@ -134,6 +134,10 @@ So, according to this rule, for a separate call to be valid, the target of the c
In the code above, <code>my_separate_attribute</code> is a class attribute declared as a separate type. In the first line in <code>calling_routine</code> a direct feature call is made to apply <code>some_feature</code> to <code>my_separate_attribute</code>. This is an invalid separate call. The second line calls feature <code>enclosing_routine</code> and passes <code>my_separate_attribute</code> as an argument. <code>enclosing_routine</code> takes an argument of type <code>separate SOME_TYPE</code>. Within <code>enclosing_routine</code> it is valid to call <code>some_feature</code> on <code>a_arg</code>.
{{SeeAlso|The <code>launch_producer</code> feature of the [[Producer-consumer|producer-consumer]] example, a feature which exists for the purpose of compliance with the separate argument rule.}}
In <code>calling_routine</code> above, the call to <code>enclosing_routine</code> has a separate argument:
<code>
@@ -146,10 +150,12 @@ Because the argument <code>my_separate_argument</code> is of a separate type, th
{{Rule|name=Wait|text=A routine call with separate arguments will execute when all corresponding processors are available and hold them exclusively for the duration of the routine.}}
{{SeeAlso|The <code>launch_producer</code> feature of the [[Producer-consumer|producer-consumer]] example, a feature which exists for the purpose of compliance with the separate argument rule.}}
{{SeeAlso|The <code>{PHILOSOPHER}.eat</code> feature of the [[Dining philosophers|dining philosophers]] example. This feature has two separate arguments, and will wait to execute until the processors associated with both are available.}}
Valid targets for separate calls, like <code>a_arg</code> in <code>enclosing_routine</code> are said to be ''controlled''.
===Controlled expressions===
Valid targets for separate calls, like <code>a_arg</code> in <code>enclosing_routine</code> above are said to be ''controlled''.
{{definition|Controlled expression|An expression is controlled if it is attached and either:<br/>1) It is of a non-separate type<br/>2) It is of a separate type and it is handled by the same processor as one of the separate arguments to the enclosing routine.}}

View File

@@ -1,8 +1,6 @@
[[Property:title|Dining philosophers]]
[[Property:weight|-12]]
[[Property:uuid|569f012e-7913-fbdf-7ad7-cd17d82e64aa]]
{{UnderConstruction}}
{{Beta}}
@@ -12,14 +10,48 @@
In the [http://en.wikipedia.org/wiki/Dining_philosophers_problem dining philosopers] a number of philosophers (five, in our example) are seated at a round table. On the table are five plates of food, one in front of each philosopher, and five forks, one between each adjacent pair of plates. So each philosopher has a plate in front of him and a fork to his left and a fork to his right.
The philosophers spend all their time in either of only two states: they are thinking or they are eating. The philosophers may be brilliant thinkers, but apparently manual dexterity is not their strong suit. This is evidenced by the fact that while eating, any philosopher must pick up both of the forks positioned next to his plate. So, while eating he must have possession of both forks, and while thinking, he has put down any forks that he had previously used. Therefore, any particular philosopher has the opportunity to eat only when the two philosophers on either side of him are thinking and have made their forks available.
The philosophers spend all their time in either of only two states: they are thinking or they are eating. The philosophers may be brilliant thinkers, but apparently manual dexterity is not their strong suit. This is evidenced by the fact that in order to eat, any philosopher must be able to pick up both of the forks positioned next to his plate (which he can do, so long as the philosopher next to him has not already done so). So, while eating he must have possession of both forks, and while thinking, he has put down any forks that he had previously used. Therefore, any particular philosopher has the opportunity to eat only when the two philosophers on either side of him are thinking and have made their forks available.
Apart from any negative consequences of these questionable sanitary practices, the dining philosophers can, in improperly designed solutions, encounter problems related to concurrency. For example, if all philosophers were to pick up the fork to their right and then wait for the fork to their left to become available (or vice versa), they would achieve a ''deadlock''. A ''starvation'' situation might occur if, because of unfairness in the solution algorithm, one or more philosophers get stuck in thinking mode because they can never secure the two forks necessary to eat.
Apart from any negative consequences from these questionable sanitary practices, the dining philosophers can, in improperly designed solutions, encounter problems related to concurrency. For example, if all philosophers were to pick up the fork to their right and then wait for the fork to their left to become available (or vice versa), they would achieve a ''deadlock''. A ''starvation'' situation might occur if, because of unfairness in the solution algorithm, one or more philosophers get stuck in thinking mode because they can never secure the two forks necessary to eat.
=Highlights=
This example includes three classes relevant to the problem: <code>APPLICATION</code>, <code>PHILOSOPHER</code>, and <code>FORK</code>. Class <code>APPLICATION</code> sets the problem in motion by creating the forks and philosophers all typed as <code>separate</code>, and then applying the feature <code>live</code> to each philosopher after creation.
Class <code>PHILOSOPHER</code> models the philosophers. The totality of a philosopher's exciting activities is modeled by the feature <code>step</code>:
<code>
step
-- Perform a philosopher'’s tasks.
do
think
eat (left_fork, right_fork)
end
</code>
This feature is called by <code>{PHILOSOPHER}.live</code> repeatedly until the philosopher has eaten a prescribed number of times.
The feature <code>think</code> requires no access to shared objects, but the feature <code>eat</code> depends upon the philosopher's ability to secure access to both of the forks adjacent to his plate. Because all forks are separate objects, each call to <code>eat</code> waits until the processors for both the left and right forks are available (in accordance with the Wait rule).
Another interesting feature of this example is the feature <code>{PHILOSOPHER}.eat</code>. If you look at the text of this feature
<code>
eat (l, r: separate FORK)
-- Eat, having grabbed l and r.
do
io.put_string ("Philosopher " + id.out + ": taking forks%N")
times_eaten := times_eaten + 1
io.put_string ("Philosopher " + id.out + ": eating%N")
io.put_string ("Philosopher " + id.out + ": putting forks back%N")
end
</code>
and you're not wearing your SCOOP glasses, this could look a little odd to you. Here is a routine that takes two arguments <code>l</code> and <code>r</code> representing the left and right forks. But then, <code>l</code> and <code>r</code> are never used in body of the routine!
However, with SCOOP in mind, we realize that the fork objects are shared resources to which exclusive access must be secured before a philosopher can eat. In this example, the fork object themselves don't really do anything except serve that purpose. (Take a look at the FORK class, and you'll see that it has no features.)
In other concurrency problems, it is likely that shared resources would play a more active role than the forks of the dining philosophers, but here it's just not necessary.