- •Лекция 7: Мониторы и условные переменные
- •Монитор и переменные условия
- •Сравнение семафоров и мониторов
- •Поддержка синхронизации в языках программирования
- •Передача сообщений
- •Взаимодействие процессов на разных машинах
- •Всегда ли параллельные процессы дают выигрыш?
- •Мораль: нити очень удобны, но не бесплатны
Сравнение семафоров и мониторов
Попробуем создать на основе семафоров все необходимые для мониторов конструкции.
Во-первых с помощью семафора легко создается lock.
Как насчет такого?
Wait() { semaphore->P(); }
Signal() { semaphore->V(); }
Так грубо нельзя моделировать переменные условия, вспомним, что wait иsignal вызываются из критической секции и такое решение может привести к блокировке.
Уточним.
Wait(Lock *lock) {
lock->Release();
semaphore->P();
lock->Acquire();
}
Signal() { semaphore->V(); }
Переменные условий не имеют памяти, поэтому signal, когда никто не ждет эквивалентен пустому оператору. Последующийwait приведет к ожиданию. С семафорами это не так.
Можно ли решить проблему таким образом?
Signal() {
if(очередь семафора не пуста)
semaphore->V();
}
Нет. Во-первых не корректно смотреть на очередь семафора. Во-вторых, если остановиться в waitпосле освобожденияlock , но доP операции, то сигнал не сработает.
В принципе проблема решается. Это для самостоятельного решения.
Поддержка синхронизации в языках программирования
Проблема в том, что программист должен расставить lock в начале функции монитора иrelease в каждой точке выхода.
C
Поддержки нет необходимо отследить все выходы из функций монитора.
C++
Более проблематично, так как язык поддерживает обработку исключительных ситуаций.
Java
Имеет явную поддержку для нитей и синхронизации.
class Shared {
private int value;
public Shared(int initial){ value = initial;}
public synchronized int get() { return value; }
public synchronized void add(int incr) { value += incr; }
}
С объектом Shared связан lock, который захватывается и освобождается автоматически при входе и выходе изsynchronized методов.
Кроме того, в Java имеется операторsynchronized с помощью которого можно защищать любой участок кода. Важно, чтоlock будет освобожден, даже если выход из этого участка кода происходит в результатеexception.
synchronized (object) {
...
some_function();
...
}
Как организуется ожидание в синхронизированных методах?
void wait(long timeout);
void wait();
Как сигнализировать о наступлении события в синхронизированных методах?
void notify();
void notifyAll();
Заметим, что фактически, имеется одна условная переменная (неявная).
Разные Java машины могут вести себя по разному. Это обусловлено тем, что в языке не специфицирован механизм планирования и он может быть разным.
Передача сообщений
Семафоры и мониторы используются для синхронизации доступа к разделяемым переменным, но не имеют средств для передачи данных от одного к другому.
Механизм передачи сообщений позволяет организовать синхронизацию и взаимодействие процессов с разделенными адресными пространствами, как на одной так и на нескольких машинах.
Сообщения– передаются в виде пакетов фиксированной длины адресату
Sender: Receiver:
SendMessage(msg, msgsize, dest); ReceiveMessage(&msg) или
SendMessage(msg, msgsize, mailbox); ReceiveMessage(&buf, mailbox)
Потоки– неструктурированный поток байтов от отправителя к адресату
Sender: Receiver:
Handle = OpenConnection(destAddr); Handle = WaitForConnection();
Handle.write(buf, nBytes); While( !handle.eof() ) {
. . . Handle.read(buf, nBytes);
Handle.write(buf, nBytes); // Обработка
Handle.Close(); }
Множество разновидностей: однонаправленные и двунаправленные, с ожиданием и без ожидания, …
Адресация:
Прямая (threadID)
Косвенная через «почтовый ящик». Допускает присвоение прав на чтение-запись в почтовый ящик
Косвенная по имени сервиса. Принимающий процесс регистрирует себя в общедоступном списке сервисов. Передающий шлет сообщения в адрес сервиса.