2. Типові приклади використання
Responsiveness
Багатозадачність ОС
Виконання операцій поза UI (I/O)
Performance
Обробка даних паралельно (CPU)
Виконання кількох задач паралельно
(CPU-CPU, CPU-I/O, I/O-I/O)
3. Process
Процес визначає virtual address space
Досягається ізоляція, оскільки
- процеси не можуть напряму адресувати
пам’ять інших процесів
Також можливе спільне використання:
- спільна бібліотека може входити до
адресного простору кількох процесів
4. Процес не виконує код,
а лише надає ресурси і контекст для
виконання потоків
5. Потоки (threads) виконують код
Потоки виконуються в межах процесу
Мають доступ до всього адресного простору
процесу.
Кожен потік має свій стек викликів (локальні
змінні), вказівник поточної інструкції та
значення регістрів CPU
6. Виконання потоків у Windows
- Багатозадачна ОС
- Витісняюче планування на основі пріоритетів
- (preemptive scheduling, priority-based)
- CPU завжди виконує той потік, який має
найвищий пріоритет (і який готовий до
виконання)
7. Планування (scheduling) Windows
- Потік виконується протягом фіксованого інтервалу
часу (time slice)
- По закінченню інтервалу ОС перевіряє, чи є
готовий потік з таким же пріоритетом
- Якщо є, потік витісняється
- Як тільки з’являється потік з вищим
пріоритетом, потік витісняється
- Навіть якщо його інтервал не закінчився
9. Потік звільняє CPU, коли:
- Завершився time slice
- Переходить в стан очікування самостійно
- Диск, мережа, пам’ять (!), синхронізація
- Витісняється потоком з вищим пріоритетом
- Який закінчив щось очікувати (диск, мережа,...)
- Пріоритет якого збільшився
- Потік завершується
- …
10. Windows та Linux планують потоки,
не процеси
Наслідок:
Процес А має 1 потік
Процес Б має 9 потоків
Процес Б отримає 90% процесорного часу
(за умови однакового пріоритету потоків)
11. UI message loop
- Один GUI потік обробляє повідомлення з черги:
- Clicks, repaints, mouse moves, key presses, …
- Події обробляються послідовно
- Отже, якщо одна подія займає довгий час, решта
будуть чекати
- Отже, довготривалі події ніколи не повинні
виконуватись в UI потоці
- I/O, важкі обчислення (див. наст. слайд)
12. Довготривалі події ніколи
не повинні виконуватись в UI потоці
- UI потік не повинен блокуватись чекаючи
завершення цих операцій
- В т.ч. коли ці операції виконуються іншим потоком
- Для повернення результатів – signals and slots
- “Qt developers are used to working with this kind of
asynchronous behavior”
http://qt-project.org/doc/qt-5.0/qtcore/thread-basics.html
13. Thread pool
- Створювати і видаляти потоки дорого
- Пул потоків виконує завдання
використовуючи створений наперед набір
потоків
- Залежно від навантаження пул створює
додаткові потоки або видаляє непотрібні
14. Типові задачі
- Поділити дані на частини і обробляти
паралельно
- Виконувати декілька незалежних задач
паралельно
- Виконати довготривалу операцію поза UI
21. Використання спільних даних
count = 0
Потік A Потік B
int temp = count; // 0
int temp = count; // 0
temp = temp + 1; // 1
temp = temp + 1; // 1
count = temp; // 1
count = temp; // 1
count = 1 // WRONG! Should be 2
22. Доступ до спільних даних повинен
бути синхронізованим
auto count = 0;
std::mutex mutex;
mutex.lock();
{ // ...
mutex.unlock();
{
std::lock_guard<std::mutex> lock(mutex);
count++;
});
Qt has its own bicycle
}
for this
23. Використання спільних даних
count = 0
Потік A Потік B
mutex.lock();
int temp = count; // 0
mutex.lock();
temp = temp + 1; // 1
count = temp; // 1
mutex.unlock();
int temp = count; // 0
temp = temp + 1; // 1
count = temp; // 1
mutex.unlock();
24. Синхронізацією керувати складно
Багато нюансів, про які ми навіть не
здогадуємось (як з count++)
Second order ignorance http://c2.com/cgi/wiki?OrdersOfIgnorance
Використовуйте готові засоби: алгоритми,
конкурентні колекції, tasks, futures,
QtConcurrent, QThreadPool, signals and slots
25. Advanced Qt
• Thread-safety and reentrance
• Working with threads
• Basic synchronization techniques
• High-level concurrency API
26. Working with threads
• QThread - a wrapper around OS thread
• do not subclass QThread
• push processing objects to QThread instance
• do not allocate heap memory in processing
object constructor
• be sure that thread is shut down when
deleting QThread
• be careful while connecting signals/slots in
multithreading applications