5.4 Семафори
Основен принцип: два или повече процеса се кооперират
в смисъл на прости сигнали така, че един процес може да бъде спрян на определено
място и да остане в това състояние, докато не получи съответен сигнал.
За да изпрати сигнал чрез семафора s,
процесът трябва да изпълни примитива (процедурата) signal(s).
За да получи сигнал от семафор s,
процесът трябва да изпълни wait(s)
и ако съответният сигнал още не е изпратен, да остане в състояние на чакане
(блокиран).
Дефинирани са 3 действия с променливата семафор:
1. Инициализира се с неотрицателно число;
2. Примитива wait(s) намалява
стойността на s с 1. Ако стойността
стане отрицателна, процесът (изпълняващ wait)
се блокира.
3. Операцията signal(s) увеличава
стойността на s с 1. Ако стойността
не е положителна, процесът (блокиран с wait)
се разблокира.
Примитивите wait и
signal
се предполат неделими, т.е. те те не могат да бъдат прекъсвани.
struct semaphore {
int count;
queueType queue;
};
void wait(semaphore s)
{ s.count--; if (s.count < 0) { place this process in s.queue; block this process; } } |
void signal(semaphore s)
{ s.count++; if (s.count <= 0) { remove a process P from s.queue; place process P on ready list; } } |
void waitB(binary_semaphore s)
{ if (s.value==one) s.value=zero; else { place this process in s.queue; block this process; } } |
void signalB(binary_semaphore s)
{ if (s.queue.is_empty()) s.value=one; else { remove a process P from s.queue; place process P on ready list; } } |
** Задачата за производител/потребител.
Един или няколко производители генерират данни (записи,
символи) и ги поставят в един буфер. Един потребител взема по една данна
от буфера. Само един агент (производител или потребител) има достъп да
буфера в даден момент.
* Първи опит за решение със семафори:
/* program producerconsumer */
int n;
binary_semaphore s = 1;
binary_semaphore delay = 0;
void producer()
{ while (true) { produce(); waitB(s); append(); n++; if (n==1) signalB(delay); signalB(s); } } |
void consumer()
{ waitB(delay); while (true) { waitB(s); take(); n--; signalB(s); consume(); if (n==0) waitB(delay); } } |
|
|
|||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* Втори опит - решение:
int n;
binary_semaphore s = 1;
binary_semaphore delay = 0;
void producer()
{ while (true) { produce(); waitB(s); append();n++; if (n==1) signalB(delay); signalB(s); } } |
void consumer()
{ int m; /* a local variable */ waitB(delay); while (true) { waitB(s); take(); n--; m = n; signalB(s); consume(); if (m==0) waitB(delay); } } |
** Задачата на бръснаря
--- FIGURE
5.19 ---
void append (char x)
{ if (count == N) cwait(notfull); /* buffer is оull;*/ /* avoid overflow */ buffer[nextin] = x; nextin = (nextin + 1) % N; count++; /* one more item in buffer */ csignal(notempty); /* resume any waiting consumer */ } |
void take (char x)
{ if (count == 0) cwait(notempty); /* buffer is empty;*/ /* avoid underflow */ x = buffer[nextout]; nextout = (nextout + 1) % N; count--; /* one fewer item in buffer */ csignal(notfull); /* resume any waiting producer */ } |
void producer()
{ char x; while (true) { produce(x); append(x); } } |
void consumer()
{ char x; while (true) { take(x); consume(x); } } |
Synchronization | Addressing | Format |
Send | Direct | Content |
blocking | send | Length |
nonblocking | receive | fixed |
Receive | explicit | variable |
blocking | implicit | |
nonblocking | Indirect | |
test for arrival | static | Queuing Discipline |
dynamic | FIFO | |
ownership | Priority |
void reader()
{ while (true) { wait(x); readcount++; if (readcount == 1) wait(wsem); signal(x); READUNIT(); wait(x); readcount--; if (readcount == 0) signal(wsem); signal(x); } } |
void writer()
{ while (true) { wait(wsem); WRITEUNIT(); signal(wsem); } }
|
void reader()
{ while (true) { wait(z); wait(rsem); wait(x); readcount++; if (readcount == 1) wait(wsem); signal(x); signal(rsem); signal(z); READUNIT(); wait(x); readcount--; if (readcount == 0) signal(wsem); signal(x); } } |
void writer ()
{ while (true) { wait(y); writecount++; if (writecount == 1) wait(rsem); signal(y); wait(wsem); WRITEUNIT(); signal(wsem); wait(y); writecount--; if (writecount == 0) signal(rsem); signal(y); } } |
* Решение на задачата с размяна на съобщения.
void readri()
{ message: rmsg; while (true) { rmsg = i; send(readrequest, rmsg); receive(mboxi, rmsg); READUNIT; rmsg = i; send(finished, rmsg); } } |
void writerj()
{ message: rmsg; while (true) { rmsg = i; send(writerequest, rmsg); receive(mboxj, rmsg); WRITEUNIT; rmsg = i; send(finished, rmsg); } } |
void controller()
{ while(true)
{ if (count > 0)
{ if (not empty(finished))
{ receive(finished,
msg);
count++;
}
else if
(not empty(writerequest))
{ receive(writerequest,
msg);
writer.id = msg.id;
count -= 100;
}
else if
(not empty(readrequest))
{ receive(readrequest,
msg);
count--;
send(msg.id, "OK");
}
}
if (count==0)
{ send(writer.id, "OK");
receive(finished,
msg);
count =
100
}
while (count<0)
{ receive(finished,
msg);
count++;
}
}
}