Page 93 - 4868
P. 93

91                                                               Ошибка! Стиль не определен.

               кожен процес-споживач Consumer – операції P(full) та V(empty).
                     4.Задача  кільцевих  буферів  (облік  ресурсів).  В  останньому  прикладі
               продемонстровано синхронний доступ до одного буфера обміну. Якщо дані
               створюються  та видаляються приблизно з однаковою частотою, то процесу
               не доводиться довго  чекати доступу до буфера. Проте зазвичай споживач  і
               виробник  працюють  нерівномірно.  Наприклад,  виробник  може  швидко
               створити відразу кілька елементів, а потім певний проміжок часу виконувати
               обчислення  перед  створенням  наступної  серії  елементів.  У  таких  випадках
               збільшення  ємності  буфера  може  істотно  підвищити  продуктивність
               програми,  зменшуючи  число  блокувань  процесів.  Даний  випадок  є
               прикладом класичного компромісу між часом обчислень і об’ємом пам’яті.

                     Розглянемо рішення задачі про кільцевий буфер, який використовується
               в  якості  багатоелементного  комунікаційного  буфера.  На  початковому  етапі
               припустимо,  що  існує  тільки  один  виробник  та  споживач.  Виробник
               розміщує  повідомлення  в  спільному  буфері,  а  споживач  витягує  їх  звідти.
               Буфер містить чергу вже поміщених, але ще не витягнутих повідомлень. Така
               черга може бути представлена зв’язаним списком або масивом. Отже, нехай
               буфер  буде  масивом  buf[n],  де  n > 1.  Нехай  змінна  front  –  індекс
               першого  повідомлення  черги,  a  rear  –  індекс  першої  порожньої  комірки
               після  повідомлення  в  кінці  черги.  Спочатку  змінні  front  та  rear  мають
               однакові значення, наприклад, 0.
                     При  такому  представленні  буфера  виробник  поміщає  в  нього
               повідомлення із значенням data, виконуючи для цього наступні дії:
                     buf[rear] = data;
                     rear = (rear+1) % n;

                     Аналогічно  споживач  витягує  повідомлення  в  свою  локальну  змінну
               result, виконуючи дії:

                     result = buf[front];
                     front = (front+1) % n;

                     Оператор взяття залишку (%) використовується для того, щоб значення
               змінних  front  та  rear  завжди  були  в  межах  від  0  до  n-1.  Черга
               буферизованих  повідомлень  зберігається  в  комірках  включно  від
               buf[front]  до  buf[rear]  (не  включно).  Змінна  buf  інтерпретується  як
               кільцевий масив, в якому за значенням  buf[n-1] слідує значення buf[0].
               Ось приклад конфігурації масиву buf, де затемнені комірки заповнені, а білі
               – вільні (рис. 1.16).







                                     Рисунок 1.16 – Конфігурація масиву buf

                     Якщо  використовується  тільки  один  буфер  (як  у  задачі  «виробник-
   88   89   90   91   92   93   94   95   96   97   98