368 lines
18 KiB
HTML
368 lines
18 KiB
HTML
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
|||
|
<html>
|
|||
|
<head>
|
|||
|
<title>Homework 3 solutions</title>
|
|||
|
</head>
|
|||
|
|
|||
|
<body>
|
|||
|
<h1>Homework 3 solutions</h1>
|
|||
|
|
|||
|
<ol start=1 type=1>
|
|||
|
<li class=MsoNormal style='mso-list:l1 level1 lfo3;tab-stops:list .5in'><b>7.1.
|
|||
|
Busy Waiting<br>
|
|||
|
<br>
|
|||
|
</b><span style='font-weight:normal'><i>Busy waiting</i></span> is
|
|||
|
continuously executing (using the CPU) while waiting for something to
|
|||
|
happen. This is typically implemented by spinning; e.g. testing a variable
|
|||
|
in a tight loop until it changes. <br>
|
|||
|
<br>
|
|||
|
The alternative to busy waiting is <i>blocking</i><span style='font-style:
|
|||
|
normal'>, where the waiting process is suspended an other processes can
|
|||
|
execute while the process is waiting.<br style='mso-special-character:
|
|||
|
line-break'>
|
|||
|
<![if !supportLineBreakNewLine]><br style='mso-special-character:line-break'>
|
|||
|
<![endif]></span></li>
|
|||
|
<li class=MsoNormal style='mso-list:l1 level1 lfo3;tab-stops:list .5in'><b>7.2.
|
|||
|
Spinlocks<br>
|
|||
|
<br>
|
|||
|
</b><span style='font-weight:normal'>Spinlocks are not appropriate for
|
|||
|
uniprocessor systems because by definition only one process is executing
|
|||
|
at a time. As a result, no other process can ever change release the lock
|
|||
|
– the scheduler has to intervene and switch out the spinning process
|
|||
|
first. As a result, the spinning process might as well suspend itself
|
|||
|
instead of spinning. Or, locking should disable interrupts to prevent the scheduler
|
|||
|
from running, so that the process is guaranteed that it can execute the
|
|||
|
entire critical section.<br>
|
|||
|
<br>
|
|||
|
On a 2 CPU multiprocessor, for example, a process scheduled on processor 1
|
|||
|
can release the lock while a process on processor 2 is spinning on it. No
|
|||
|
interrupt is needed. Thus, spinlocks are not necessarily wasteful on a
|
|||
|
multiprocessor.</span></li>
|
|||
|
</ol>
|
|||
|
|
|||
|
|
|||
|
<p class=MsoNormal>Synchronization Problems</p>
|
|||
|
|
|||
|
<p class=MsoNormal>Notes:</p>
|
|||
|
|
|||
|
<p class=MsoNormal style='margin-left:.5in;text-indent:-.25in;mso-list:l2 level1 lfo7;
|
|||
|
tab-stops:list .5in'><![if !supportLists]><span style='font-family:"Times New Roman"'>-<span
|
|||
|
style='font:7.0pt "Times New Roman"'>
|
|||
|
</span></span><![endif]>Please use real binary semaphores, counting semaphores,
|
|||
|
or monitors. If you invent your own synchronization method, there is a 99% chance
|
|||
|
you will get it wrong. Plus it makes it very hard to grade - we look very
|
|||
|
closely and are more likely to find problems. If you must do this, provide an
|
|||
|
implementation of your construct, because otherwise we don't know if:</p>
|
|||
|
|
|||
|
<p class=MsoNormal style='margin-left:1.0in;text-indent:-.25in;mso-list:l2 level2 lfo7;
|
|||
|
tab-stops:list 1.0in'><![if !supportLists]><span style='font-family:"Courier New"'>o<span
|
|||
|
style='font:7.0pt "Times New Roman"'>
|
|||
|
</span></span><![endif]>It is possible to implement</p>
|
|||
|
|
|||
|
<p class=MsoNormal style='margin-left:1.0in;text-indent:-.25in;mso-list:l2 level2 lfo7;
|
|||
|
tab-stops:list 1.0in'><![if !supportLists]><span style='font-family:"Courier New"'>o<span
|
|||
|
style='font:7.0pt "Times New Roman"'>
|
|||
|
</span></span><![endif]>How it works</p>
|
|||
|
|
|||
|
<p class=MsoNormal style='margin-left:.5in;text-indent:-.25in;mso-list:l2 level1 lfo7;
|
|||
|
tab-stops:list .5in'><![if !supportLists]><span style='font-family:"Times New Roman"'>-<span
|
|||
|
style='font:7.0pt "Times New Roman"'>
|
|||
|
</span></span><![endif]>If you use semaphores, you must specify initial values
|
|||
|
for your semaphores (mandatory).</p>
|
|||
|
|
|||
|
<p class=MsoNormal style='margin-left:.5in;text-indent:-.25in;mso-list:l2 level1 lfo7;
|
|||
|
tab-stops:list .5in'><![if !supportLists]><span style='font-family:"Times New Roman"'>-<span
|
|||
|
style='font:7.0pt "Times New Roman"'>
|
|||
|
</span></span><![endif]>If you have a shared state, you should say what mutex
|
|||
|
protects the shared state (not mandatory)</p>
|
|||
|
|
|||
|
<p class=MsoNormal style='margin-left:.5in;text-indent:-.25in;mso-list:l2 level1 lfo7;
|
|||
|
tab-stops:list .5in'><![if !supportLists]><span style='font-family:"Times New Roman"'>-<span
|
|||
|
style='font:7.0pt "Times New Roman"'>
|
|||
|
</span></span><![endif]>With semaphores, if you wake up on one semaphore and then
|
|||
|
call signal() to wake up the next waiter you might wake yourself up -
|
|||
|
semaphores have history, so your next wait might be the one that awakes,
|
|||
|
because the other waiters might have been context switchted out before they
|
|||
|
call wait().</p>
|
|||
|
|
|||
|
<p class=MsoNormal style='margin-left:.5in;text-indent:-.25in;mso-list:l2 level1 lfo7;
|
|||
|
tab-stops:list .5in'><![if !supportLists]><span style='font-family:"Times New Roman"'>-<span
|
|||
|
style='font:7.0pt "Times New Roman"'>
|
|||
|
</span></span><![endif]>With semaphores, you shouldn't wait while holding a
|
|||
|
mutex, unless the routine signaling you does not need the mutex to wake you up.</p>
|
|||
|
|
|||
|
<p class=MsoNormal style='margin-left:.5in;text-indent:-.25in;mso-list:l2 level1 lfo7;
|
|||
|
tab-stops:list .5in'><![if !supportLists]><span style='font-family:"Times New Roman"'>-<span
|
|||
|
style='font:7.0pt "Times New Roman"'>
|
|||
|
</span></span><![endif]>With monitors, you don't need to grab a mutex (or,
|
|||
|
shudder, a condition variable) to access shared state. The monitor, by
|
|||
|
definition, ensures mutual exclusion.</p>
|
|||
|
|
|||
|
<p class=MsoNormal style='margin-left:.5in;text-indent:-.25in;mso-list:l2 level1 lfo7;
|
|||
|
tab-stops:list .5in'><![if !supportLists]><span style='font-family:"Times New Roman"'>-<span
|
|||
|
style='font:7.0pt "Times New Roman"'>
|
|||
|
</span></span><![endif]>With monitors, wait() doesn't take any parameters - it
|
|||
|
just waits until somebody then calls signal().</p>
|
|||
|
|
|||
|
<p class=MsoNormal style='margin-left:.5in;text-indent:-.25in;mso-list:l2 level1 lfo7;
|
|||
|
tab-stops:list .5in'><![if !supportLists]><span style='font-family:"Times New Roman"'>-<span
|
|||
|
style='font:7.0pt "Times New Roman"'>
|
|||
|
</span></span><![endif]>When writing synchronization code, you should try to
|
|||
|
minimize the number of context switches and the number of times a process is
|
|||
|
awoken when it doesn't need to be. Ideally, in a while() loop, a process should
|
|||
|
only be woken once.<br style='mso-special-character:line-break'>
|
|||
|
<![if !supportLineBreakNewLine]><br style='mso-special-character:line-break'>
|
|||
|
<![endif]></p>
|
|||
|
|
|||
|
<ol start=3 type=1>
|
|||
|
<li class=MsoNormal style='mso-list:l1 level1 lfo3;tab-stops:list .5in'><b>7.8.
|
|||
|
Sleeping-barber problem.</b><span style='font-weight:normal'> </span></li>
|
|||
|
</ol>
|
|||
|
|
|||
|
<h2 style='margin-left:.5in;mso-list:l0 level1 lfo10'><![if !supportLists]><span
|
|||
|
style='font-size:12.0pt'><span style='font:7.0pt "Times New Roman"'>
|
|||
|
</span></span><![endif]><span style='font-size:12.0pt'>Barbershop Requirements:<o:p></o:p></span></h2>
|
|||
|
|
|||
|
<h3 style='margin-left:.5in;mso-list:l0 level1 lfo11'><![if !supportLists]><span
|
|||
|
style='font-size:10.0pt'>-<span style='font:7.0pt "Times New Roman"'>
|
|||
|
</span></span><![endif]><span style='font-size:10.0pt'>Barber sleeps if no
|
|||
|
customers waiting<o:p></o:p></span></h3>
|
|||
|
|
|||
|
<h3 style='margin-left:.5in;mso-list:l0 level1 lfo11'><![if !supportLists]><span
|
|||
|
style='font-size:10.0pt'>-<span style='font:7.0pt "Times New Roman"'>
|
|||
|
</span></span><![endif]><span style='font-size:10.0pt'>Customers leave if no
|
|||
|
chairs for waiting<o:p></o:p></span></h3>
|
|||
|
|
|||
|
<h3 style='margin-left:.5in;mso-list:l0 level1 lfo11'><![if !supportLists]><span
|
|||
|
style='font-size:10.0pt'>-<span style='font:7.0pt "Times New Roman"'>
|
|||
|
</span></span><![endif]><span style='font-size:10.0pt'>Waiting customers can't
|
|||
|
leave until haircut done.<o:p></o:p></span></h3>
|
|||
|
|
|||
|
<h2 style='margin-left:.5in;mso-list:l0 level1 lfo10'><![if !supportLists]><span
|
|||
|
style='font-size:12.0pt'><span style='font:7.0pt "Times New Roman"'>
|
|||
|
</span></span><![endif]><span style='font-size:12.0pt'>Solution: we use
|
|||
|
semaphores<o:p></o:p></span></h2>
|
|||
|
|
|||
|
<h3 style='margin-left:.5in;mso-list:l0 level1 lfo11'><![if !supportLists]><span
|
|||
|
style='font-size:10.0pt'>-<span style='font:7.0pt "Times New Roman"'>
|
|||
|
</span></span><![endif]><span style='font-size:10.0pt'>Mutex = 1<o:p></o:p></span></h3>
|
|||
|
|
|||
|
<h3 style='margin-left:.5in;mso-list:l0 level1 lfo11'><![if !supportLists]><span
|
|||
|
style='font-size:10.0pt'>-<span style='font:7.0pt "Times New Roman"'>
|
|||
|
</span></span><![endif]><span style='font-size:10.0pt'>counting:
|
|||
|
barber_sleeping, customer_queue, cut_done<o:p></o:p></span></h3>
|
|||
|
|
|||
|
|
|||
|
<b>Barber Code</b><br>
|
|||
|
<br>
|
|||
|
|
|||
|
<pre>
|
|||
|
wait(mutex)
|
|||
|
if (customers_waiting == 0) {
|
|||
|
signal(mutex);
|
|||
|
wait(barber_sleeping);
|
|||
|
wait(mutex);
|
|||
|
}
|
|||
|
customers_waiting--;
|
|||
|
signal(mutex);
|
|||
|
signal(customer_queue);
|
|||
|
do_cut_hair();
|
|||
|
signal(cut_done);
|
|||
|
</pre>
|
|||
|
|
|||
|
<b>Customer Code</b><br>
|
|||
|
|
|||
|
<pre>
|
|||
|
wait(mutex);
|
|||
|
if (customers_waiting == n) {
|
|||
|
signal(mutex);
|
|||
|
return;
|
|||
|
}
|
|||
|
customers_waiting++;
|
|||
|
if (customers_waiting == 1) {
|
|||
|
signal(barber_sleeping);
|
|||
|
}
|
|||
|
signal(mutex);
|
|||
|
wait(customer_queue);
|
|||
|
get_hair_cut();
|
|||
|
wait(cut_done);
|
|||
|
</pre>
|
|||
|
|
|||
|
<b>As a monitor</b>
|
|||
|
|
|||
|
<pre>
|
|||
|
monitor barbershop {
|
|||
|
int num_waiting;
|
|||
|
condition get_cut;
|
|||
|
condition barber_asleep;
|
|||
|
condition in_chair;
|
|||
|
condition cut_done;
|
|||
|
|
|||
|
Barber routine
|
|||
|
barber() {
|
|||
|
while (1);
|
|||
|
while (num_waiting == 0) {
|
|||
|
barber_asleep.wait();
|
|||
|
}
|
|||
|
customer_waiting.signal();
|
|||
|
in_chair.wait();
|
|||
|
give_hait_cut();
|
|||
|
cut_done.signal();
|
|||
|
}
|
|||
|
Customer routine
|
|||
|
customer () {
|
|||
|
if (num_waiting == n) {
|
|||
|
return;
|
|||
|
}
|
|||
|
if (num_waiting == 0) {
|
|||
|
barber_asleep.signal();
|
|||
|
}
|
|||
|
customer_waiting.wait();
|
|||
|
in_char.signal();
|
|||
|
get_hair_cut();
|
|||
|
cut_done.wait();
|
|||
|
}
|
|||
|
</pre>
|
|||
|
|
|||
|
<p style='margin-left:.5in;tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><![if !supportEmptyParas]> <![endif]><o:p></o:p></p>
|
|||
|
|
|||
|
<p style='margin-left:.5in;text-indent:-.25in;mso-list:l1 level1 lfo3;
|
|||
|
tab-stops:list .5in'><![if !supportLists]>7.<span style='font:7.0pt "Times New Roman"'>
|
|||
|
</span><![endif]><b>7.9. The Cigarette-Smokers Problem.</b><span
|
|||
|
style='font-weight:normal'> </span></p>
|
|||
|
|
|||
|
<p style='margin-left:.5in;tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'>Semaphores
|
|||
|
are a convenient mechanism for implementing this, because they remember what
|
|||
|
elements are on the table.</p>
|
|||
|
|
|||
|
<p style='margin-left:.5in;tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span
|
|||
|
style='font-family:"Courier New"'>Sempahore TobaccoAndPaper = 0;<br>
|
|||
|
Sempahore PaperAndMatches = 0;<br>
|
|||
|
Semaphore MatchesAndTobacco = 0;<br>
|
|||
|
Sempaphore DoneSmoking = 1;<o:p></o:p></span></p>
|
|||
|
|
|||
|
<p class=MsoNormal style='margin-left:.5in;tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span
|
|||
|
style='font-family:"Courier New"'>void agent() <br>
|
|||
|
{<br>
|
|||
|
wait(DoneSmoking);<br>
|
|||
|
int r = rand() % 3;<o:p></o:p></span></p>
|
|||
|
|
|||
|
<p class=MsoNormal style='margin-left:.5in;tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span
|
|||
|
style='font-family:"Courier New"'><br>
|
|||
|
//<br>
|
|||
|
// Signal which ever combination was<br>
|
|||
|
// chosen.<br>
|
|||
|
//<br style='mso-special-character:line-break'>
|
|||
|
<![if !supportLineBreakNewLine]><br style='mso-special-character:line-break'>
|
|||
|
<![endif]><o:p></o:p></span></p>
|
|||
|
|
|||
|
<p class=MsoNormal style='margin-left:.5in;tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span
|
|||
|
style='font-family:"Courier New"'><br>
|
|||
|
switch( r ) {<br>
|
|||
|
case 0:
|
|||
|
signal(TobaccoAndPaper);<br>
|
|||
|
break;<br>
|
|||
|
case 1:
|
|||
|
signal(PaperAndMatches);<br>
|
|||
|
break;<br>
|
|||
|
case 2:
|
|||
|
signal(MatchesAndTobacco);<br>
|
|||
|
break;<br>
|
|||
|
}<br>
|
|||
|
}<br>
|
|||
|
<br>
|
|||
|
void Smoker_A()<br>
|
|||
|
{<br>
|
|||
|
while(true) {<br>
|
|||
|
<br>
|
|||
|
//<br>
|
|||
|
// Wait for our
|
|||
|
two ingredients<br>
|
|||
|
//<br>
|
|||
|
<br>
|
|||
|
|
|||
|
wait(TobaccoAndPaper);<br>
|
|||
|
smoke();<br>
|
|||
|
<br>
|
|||
|
//<br>
|
|||
|
// Signal that
|
|||
|
we're done smoking<br>
|
|||
|
// so the next
|
|||
|
agent can put down<br>
|
|||
|
// ingredients.<br>
|
|||
|
//<br>
|
|||
|
<br>
|
|||
|
|
|||
|
signal(DoneSmoking);<br>
|
|||
|
}<br>
|
|||
|
}<br style='mso-special-character:line-break'>
|
|||
|
<![if !supportLineBreakNewLine]><br style='mso-special-character:line-break'>
|
|||
|
<![endif]></span></p>
|
|||
|
|
|||
|
<p class=MsoNormal style='margin-left:.5in;tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'>Smoker
|
|||
|
b and c are similar.<span style='font-family:"Courier New"'><o:p></o:p></span></p>
|
|||
|
|
|||
|
<p style='margin-left:.5in;tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span
|
|||
|
style="mso-spacerun: yes"> </span></p>
|
|||
|
|
|||
|
<pre style='margin-left:.5in'><span style="mso-spacerun: yes"> </span></pre>
|
|||
|
|
|||
|
<p style='margin-left:.5in;text-indent:-.25in;mso-list:l1 level1 lfo3;
|
|||
|
tab-stops:list .5in'><![if !supportLists]>8.<span style='font:7.0pt "Times New Roman"'>
|
|||
|
</span><![endif]><b>7.15. File-synchronization</b><span style='font-weight:
|
|||
|
normal'> </span></p>
|
|||
|
|
|||
|
<p style='margin-left:.5in;tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'>
|
|||
|
From the book you should know how to use a <i>conditional-wait</i><span
|
|||
|
style='font-style:normal'> construct (priority-based signaling), so we'll use it here. We'll assume for simplicity that no
|
|||
|
process has an id greater than or equal to n (or we'd just print an error
|
|||
|
message). </span></p>
|
|||
|
|
|||
|
<pre style='margin-left:.5in'><![if !supportEmptyParas]> <![endif]><o:p></o:p></pre><pre
|
|||
|
style='margin-left:.5in'> type file = monitor</pre><pre style='margin-left:
|
|||
|
.5in'><span style="mso-spacerun: yes"> </span>var space_available: binary condition</pre><pre
|
|||
|
style='margin-left:.5in'><span style="mso-spacerun: yes"> </span>total: integer</pre><pre
|
|||
|
style='margin-left:.5in'> </pre><pre style='margin-left:.5in'><span style="mso-spacerun: yes"> </span>procedure entry file_open(id)</pre><pre
|
|||
|
style='margin-left:.5in'><span style="mso-spacerun: yes"> </span>begin</pre><pre
|
|||
|
style='margin-left:.5in'><span style="mso-spacerun: yes"> </span>while (total + id >= n)</pre><pre
|
|||
|
style='margin-left:.5in'><span style="mso-spacerun: yes"> </span>space_available.wait(id)</pre><pre
|
|||
|
style='margin-left:.5in'><span style="mso-spacerun: yes"> </span>total = total + id;</pre><pre
|
|||
|
style='margin-left:.5in'><span style="mso-spacerun: yes"> </span>if (total < n - 1)</pre><pre
|
|||
|
style='margin-left:.5in'><span style="mso-spacerun: yes"> </span>space_available.signal();</pre><pre
|
|||
|
style='margin-left:.5in'><span style="mso-spacerun: yes"> </span>end</pre><pre
|
|||
|
style='margin-left:.5in'><![if !supportEmptyParas]> <![endif]><o:p></o:p></pre><pre
|
|||
|
style='margin-left:.5in'><span style="mso-spacerun: yes"> </span>procedure entry file_close(id)</pre><pre
|
|||
|
style='margin-left:.5in'><span style="mso-spacerun: yes"> </span>begin</pre><pre
|
|||
|
style='margin-left:.5in'><span style="mso-spacerun: yes"> </span>total = total - id;</pre><pre
|
|||
|
style='margin-left:.5in'><span style="mso-spacerun: yes"> </span>space_available.signal();</pre><pre
|
|||
|
style='margin-left:.5in'><span style="mso-spacerun: yes"> </span>end</pre>
|
|||
|
|
|||
|
<p class=MsoNormal style='margin-left:.5in;tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'>What
|
|||
|
happens here? As long as the incoming processes find adequate space available
|
|||
|
(i.e. sums less than n), they will claim that space and open the file. Note
|
|||
|
that since we're using a binary condition, we can signal() at will even if
|
|||
|
nothing is waiting. If a process finds inadequate space, it will block. When a
|
|||
|
process is done, it wakes up the process with the smallest id (the most likely
|
|||
|
to fit in the available space). This process, upon waking, then signals the
|
|||
|
next process if space is still available, but only after successfully claiming
|
|||
|
its own space. At some point (quite possibly with the first process), the space
|
|||
|
made available may not be enough for the waking process, and so a process will
|
|||
|
be woken up prematurely. This is what the loop is for; it will immediately
|
|||
|
block again. </p>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<ol start=6 type=1>
|
|||
|
<li class=MsoNormal style='mso-list:l1 level1 lfo3;tab-stops:list .5in'><b>8.4
|
|||
|
b<br>
|
|||
|
</b>install traffic lights :)
|
|||
|
<br>
|
|||
|
<li class=MsoNormal style='mso-list:l1 level1 lfo3;tab-stops:list .5in'><b>8.8
|
|||
|
<br>
|
|||
|
</b>The system can always make progress in all possible
|
|||
|
allocation scenarios (use pigeonhole principle to show this).
|
|||
|
</ol>
|
|||
|
<hr>
|
|||
|
</body>
|
|||
|
</html>
|