Задача о читателях и писателях

advertisement
Java Advanced
Многопоточное
программирование
Краткое содержание
1. Введение
2. Классические задачи многопоточного
программирования
3. Атомарные операции
4. Примитивы синхронизации
5. Решения задач многопоточного
программирования
6. Заключение
Georgiy Korneev
2
Часть 1
Введение
Многопоточное программирование
Программа одновременно имеет
несколько потоков исполнения
 Потоки должны взаимодействовать
(синхронизироваться) друг с другом

Georgiy Korneev
4
Пример. Умножение матриц
// Матрицы размера n на n
double[][] a, b, c;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
c[i][j] = 0;
for (int k = 0; k < n; k++) {
c[i][j] += a[i][k] * b[k][j];
}
}
}
Georgiy Korneev
5
Пример. Итеративный параллелизм
// Матрицы размера n на n
double[][] a, b, c;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
c[i][j] = 0;
for (int k = 0; k < n; k++) {
c[i][j] += a[i][k] * b[k][j];
}
}
}
Georgiy Korneev
// Параллельно
// Параллельно
6
Пример. Обмен сообщениями (1)

Рабочий поток
Worker[i] {
double[] a;
// a[i][*]
double[][] b;
// b[*][*]
double[] c;
// c[i][*]
receive a, b from coordinator;
for (int j = 0; j < n; j++) {
c[j] = 0;
for (int k = 0; k < n; k++) {
c[j] += a[k] * b[k][j];
}
}
send c to coordinator;
}
Georgiy Korneev
7
Пример. Обмен сообщениями (2)

Управляющий поток
coordinator(int i) {
double[][] a, b, c;
for (int i = 0; i < n; i++) {
send a[i], b to worker[i];
}
for (int i = 0; i < n; i++) {
receive c[i] from worker[i];
}
}
Georgiy Korneev
8
Пример. Обмен сообщениями (3)
worker[i] {
double[] a; // a[i][*]
double[] b; // b[*][i]
double[] c; // a[i][*]
receive a, b from coordinator;
for (int j = 0; j < n; j++) {
double s = 0;
for (int k = 0; k < n; k++) {
s += a[k] * b[k];
}
c[(i + j) % n] = s;
send b to worker[(i + 1) % n];
receive b from worker[(i + n - 1) % n];
}
send c to coordinator;
}
Georgiy Korneev
9
Пример. Вычисление интеграла

Адаптивное вычисление интеграла f(x)
double integrate(double l, double r) {
if (abs(area(l, m) + area(m, r) - area(l, r)) > EPS) {
return integrate(l, m) + integrate(m, r);
} else {
return area(l, m) + area(m, r);
}
}
double area(double l, double r) {
return (f(l) + f(r)) * (r - l) / 2;
}
Georgiy Korneev
10
Пример. Рекурсивный параллелизм

Адаптивное вычисление интеграла f(x)
double integrate(double l, double r) {
double m = (l + r) / 2;
double la = area(l, m);
double ra = aread(m, r);
if (abs(la + ra - area(l, r)) > EPS) {
la = integrate(l, m); // Параллельно
ra = integrate(m, r); // Параллельно
}
return la + ra;
}
Georgiy Korneev
11
Основные операции
Создание потока
 Уничтожение потока
 Неделимая операция

statements

Неделимая операция с ожиданием
условия
await(C) statements
Georgiy Korneev
12
Пример. Поиск максимума (1)

Без синхронизации
int max = 0;
create worker[i] {
if (max < a[i]) max = a[i];
}

С синхронизацией
int max = 0;
create worker[i] {
if (max < a[i]) max = a[i];
}
Georgiy Korneev
13
Пример. Поиск максимума (2)

Протокол Проверить-ПроверитьУстановить
int max = 0;
create worker[i] {
if (max < a[i]) {
 if (max < a[i]) max = a[i]; 
}
}
Georgiy Korneev
14
Свойства планирования

Справедливость



Безусловная
Слабая
Сильная
Безопасность
 Живучесть

Georgiy Korneev
15
Часть 2
Классические задачи
многопоточного
программирования
Задача доступа к общему ресурсу

Несколько потоков обращаются к общему
ресурсу
T2
T1
Georgiy Korneev
T3
R
T4
T5
17
Производитель-потребитель
Один поток производит данные, второй их
потребляет
 Несколько потоков производят данные и
несколько их потребляют
 Данные могут храниться в очереди
(не)ограниченного объема

P
Georgiy Korneev
Data
C
18
Задача о читателях и писателях
Читать могут много потоков одновременно
 Писать может только один поток
 Читать во время записи нельзя

W1
R1
Data
WN
Georgiy Korneev
RN
19
Задача об обедающих философах
5 Философов, 5
тарелок, 5 вилок
 Философ




Думает
Ест
Что бы есть нужны
обе вилки
Georgiy Korneev
20
Задания-работники

Поток-клиент ждет выполнения задания
потоком-сервером
C1
W1
Queue
CN
Georgiy Korneev
WN
21
Часть 3
Атомарные операции
Атомарная операция

Операция выполняемая как единое целое



Чтение
Запись
Неатомарные операции


Инкремент
Декремент
Georgiy Korneev
23
Виды атомарных операций

Операция чтения


Операция записи


set
Операции записи и чтения



get
addAndGet, incAndGet, …
getAndAdd, getAndInc, …
Операция условной записи

compareAndSet
Georgiy Korneev
24
Решение задачи доступа к ресурсу
// Получение доступа к ресурсу
while(!v.compareAndSet(0, 1));
// Действия с ресурсом
// Освобождение ресурса
v.set(0);
Georgiy Korneev
25
Часть 4
Примитивы
синхронизации
Критическая секция


Только один поток может выполнять
действия в критической секции
Именованные критические секции
< name: statements >
Georgiy Korneev
27
Решение задачи доступа к ресурсу

Доступ производится в критической секции
resource
<
resource:
// Доступ к ресурсу
>
Georgiy Korneev
28
Реализации критических секций

На основе блокировки




 await(!lock) lock = true; 
// Критическая секция
lock = false;
// Вход
// Выход
На основе атомарных операций



while(!lock.compareAndSet(0, 1));
// Критическая секция
lock.set(0);
Georgiy Korneev
// Вход
// Выход
29
Блокировка (lock, mutex)



Только один поток может владеть
блокировкой
Могут быть использованы для передачи
событий
Операции



lock
unlock
tryLock
Georgiy Korneev
получить блокировку
отдать блокировку
попробовать получить блокировку
30
Решение задачи доступа к ресурсу

Доступ ограничен блокировкой lock
// Получение блокировки
lock.lock();
// Доступ к ресурсу
// Освобождение блокировки
lock.unlock()
Georgiy Korneev
31
Семафор



Хранит количество разрешений на вход
Могут быть использованы для передачи
событий
Операции



acquire
получить разрешение
release
добавить разрешение
tryAcquire попробовать получить разрешение
Georgiy Korneev
32
Барьер

Потоки блокируются пока все потоки не
прибудут к барьеру



Одноразовый
Многоразовый
Операции

arrive прибытие к барьеру
Georgiy Korneev
33
Монитор




Разделяемые переменные
инкапсулированы в мониторе
Код в мониторе исполняется не более чем
одним потоком
Условия
Операции с условиями



wait
ожидание условия
notify
сообщение об условии одному потоку
notifyAll сообщение об условии всем потокам
Georgiy Korneev
34
Часть 5
Решение классических
задач параллельного
программирования
Производитель-потребитель

Решение с помощью разделенных
блокировок

Производитель
empty.lock();
// копирование
full.unlock();

Потребитель
full.lock();
// копирование
empty.unlock();
Georgiy Korneev
36
Задания-работники

Решение с помощью монитора

Задание
queue.add(task);
queue.notify();
task.wait();

Работник
while (queue.isEmpty()) queue.wait();
Task t = queue.get();
// Обработка задания
t.notify();
Georgiy Korneev
37
Задача об обедающих философах

Решение с помощью асимметрии


Все философы кроме одного берут сначала
левую, затем правую вилку
Оставшийся философ берет сначала правую,
затем левую вилку
Georgiy Korneev
38
Задача о читателях и писателях (1)

Решение с помощью блокировки

Читатель
 if (nr++ == 0) busy.lock(); 
// Чтение
 if (--nr == 0) busy.unlock(); 

Писатель
busy.lock();
// Запись
busy.unlock();
Georgiy Korneev
39
Задача о читателях и писателях (2)
Решение с помощью передачи эстафеты
 Особенности решения





Если есть и писатели и читатели, то вход
закрывается
Пока есть читатели – разрешать чтение
Когда нет читателей – разрешить запись
Когда нет ни читателей ни писателей – открыть
вход
Georgiy Korneev
40
Задача о читателях и писателях (3)
e
dr
dw
r
w
nr
nw
Data
e
Georgiy Korneev
41
Задача о читателях и писателях

Передача эстафеты
if (nw == 0 && dr > 0) {
dr--;
r.unlock(); // Возобновить процесс-читатель
} else if (nr == 0 && nw == 0 && dw > 0) {
dw--;
w.unlock(); // Возобновить процесс-писатель
} else {
e.unlock(); // Открыть вход
}
Georgiy Korneev
42
Задача о читателях и писателях

Читатель
e.lock();
if (nw > 0) { dr++; e.unlock(); r.lock(); }
// Доступ разрешен
nr++;
// Передача эстафеты
// Чтение
e.lock();
nr--;
// Передача эстафеты
Georgiy Korneev
43
Задача о читателях и писателях

Писатель
e.lock();
if (nw > 0 || nr > 0) { dw++; e.unlock(); w.lock(); }
nw++;
// Передача эстафеты
// Запись
e.lock();
nw--;
// Передача эстафеты
Georgiy Korneev
44
Часть 6
Заключение
Ссылки



Эндрюс Г. Основы многопоточного,
параллельного и распределенного
программирования
Lea D. Concurrent Programming in Java
Garg V. Concurrent and Distributed
Computing in Java
Georgiy Korneev
46
Вопросы
Georgiy Korneev
47
Download