Чтение онлайн

на главную - закладки

Жанры

QT 4: программирование GUI на С++

Саммерфилд Марк

Шрифт:

Другой подход к решению проблемы синхронизации работы потока, формирующего данные, и потока, принимающего данные, состоит в применении классов QWaitCondition и QMutex. Класс QWaitCondition позволяет одному потоку «пробуждать» другие потоки, когда удовлетворяется некоторое условие. Этим обеспечивается более точное управление, чем путем применения только одних мьютексов. Чтобы показать, как это работает, мы переделаем пример с двумя потоками, используя условия ожидания.

const int DataSize = 100000;

const int BufferSize = 4096;

char buffer[BufferSize];

QWaitCondition bufferIsNotFull;

QWaitCondition bufferIsNotEmpty;

QMutex mutex;

int usedSpace = 0;

Кроме

буфера мы объявляем два объекта QWaitCondition, один объект QMutex и одну переменную для хранения количества «использованных» байтов в буфере.

01 void Producer::run

02 {

03 for (int i = 0; i < DataSize; ++i) {

04 mutex.lock;

05 while (usedSpace == BufferSize)

06 bufferIsNotFull.wait(&mutex);

07 buffer[i % BufferSize] = "ACGT"[uint(rand) % 4];

08 ++usedSpace;

09 bufferIsNotEmpty.wakeAll;

10 mutex.unlock;

11 }

12 }

Работу потока, формирующего данные, мы начинаем с проверки заполнения буфера. Если он заполнен, мы ждем возникновения условия «буфер не заполнен». Когда это условие удовлетворяется, мы записываем один байт в буфер, увеличиваем на единицу usedSpace и возобновляем работу любого потока, ожидающего возникновения условия «буфер не пустой».

Мы используем мьютекс для контроля любого доступа к переменной usedSpace. Функция QWaitCondition::wait может принимать в первом своем аргументе заблокированный мьютекс, который она открывает перед блокировкой текущего потока и затем вновь блокирует его перед выходом.

В этом примере мы могли бы заменить цикл while

while (usedSpace == BufferSize)

bufferIsNotFull.wait(&mutex);

на инструкцию if:

if (usedSpace == BufferSize) {

mutex.unlock;

bufferIsNotFull.wait;

mutex.lock;

}

Однако это не будет правильно работать, как только мы станем использовать несколько потоков, формирующих данные, поскольку другой такой поток может захватить мьютекс сразу же после вызова функции wait и вновь отменить условие «буфер не заполнен».

01 void Consumer::run

02 {

03 for (int i = 0; i < DataSize; ++i) {

04 mutex.lock;

05 while (usedSpace == 0)

06 bufferIsNotEmpty.wait(&mutex);

07 cerr << buffer[i % BufferSize];

08 --usedSpace;

09 bufferIsNotFull.wakeAll;

10 mutex.unlock;

11 }

12 cerr << endl;

13 }

Поток—приемник

работает в точности наоборот относительно первого потока: он ожидает возникновения условия «буфер не пустой» и возобновляет работу любого потока, ожидающего условия «буфер не заполнен».

Во всех приводимых до сих пор примерах наши потоки имеют доступ к одинаковым глобальным переменным. Но для некоторых многопоточных приложений требуется хранить в глобальных переменных неодинаковые данные для разных потоков. Эти переменные часто называют локальной памятью потока (thread-local storage — TLS) или специальными данными потока (thread-specific data — TSD). Мы можем «схитрить» и использовать отображение, в качестве ключей которого применяются идентификаторы потоков (возвращаемые функцией QThread::currentThread), но более привлекательное решение состоит в использовании класса QThreadStorage<T>.

Обычно класс QThreadStorage<T> используется для кэш—памяти. Имея отдельный кэш для каждого потока, мы избегаем затрат, связанных с блокировкой, разблокировкой и возможным ожиданием освобождения мьютекса. Например:

01 QThreadStorage<QHash<int, double> *> cache;

02 void insertIntoCache(int id, double value)

03 {

04 if (!cache.hasLocalData)

05 cache.setLocalData(new QHash<int, double>);

06 cache.localData->insert(id, value);

07 }

08 void removeFromCache(int id)

09 {

10 if (cache.hasLocalData)

11 cache.localData->remove(id);

12 }

Переменная cache содержит указатель на используемое потоком отображение QHash<int, double>. (Из-за проблем с некоторыми компиляторами тип объекта, задаваемый в шаблонном классе QThreadStorage<T>, должен быть указателем.) При применении первый раз кэша в потоке функция hasLocalData возвращает false, и мы создаем объект типа QHash<int, double>.

Кроме кэширования класс QThreadStorage<T> может использоваться для глобальных переменных, отражающих состояние ошибки (подобных errno), чтобы модификации в одном потоке не влияли на другие потоки.

Взаимодействие с главным потоком

При запуске приложения Qt работает только один поток — главный. Только этот поток может создать объект QApplication или QCoreApplication и вызвать для него функцию exec. После вызова exec этот поток либо ожидает возникновения какого-нибудь события, либо обрабатывает какое-нибудь событие.

Поделиться:
Популярные книги

Кодекс Охотника. Книга IV

Винокуров Юрий
4. Кодекс Охотника
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Кодекс Охотника. Книга IV

Русские дети (сборник)

Фрай Макс
Проза:
современная проза
5.60
рейтинг книги
Русские дети (сборник)

Князь Целитель 4

Ткачев Андрей Юрьевич
4. Князь Целитель
Фантастика:
боевая фантастика
городское фэнтези
аниме
фэнтези
5.00
рейтинг книги
Князь Целитель 4

Убивать чтобы жить 3

Бор Жорж
3. УЧЖ
Фантастика:
героическая фантастика
боевая фантастика
рпг
5.00
рейтинг книги
Убивать чтобы жить 3

Темный Лекарь 9

Токсик Саша
9. Темный Лекарь
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Темный Лекарь 9

Черный маг императора

Герда Александр
1. Черный маг императора
Фантастика:
юмористическая фантастика
попаданцы
аниме
5.00
рейтинг книги
Черный маг императора

Прапорщик. Назад в СССР. Книга 6

Гаусс Максим
6. Второй шанс
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Прапорщик. Назад в СССР. Книга 6

В лапах зверя

Зайцева Мария
1. Звериные повадки Симоновых
Любовные романы:
остросюжетные любовные романы
эро литература
5.00
рейтинг книги
В лапах зверя

Хозяин Теней

Петров Максим Николаевич
1. Безбожник
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Хозяин Теней

Евреи России. Времена и события. История евреев Российской империи

Кандель Феликс Соломонович
Научно-образовательная:
история
5.00
рейтинг книги
Евреи России. Времена и события. История евреев Российской империи

Четники. Королевская армия

Тимофеев Алексей Юрьевич
Документальная литература:
биографии и мемуары
публицистика
5.00
рейтинг книги
Четники. Королевская армия

Цеховик. Книга 2. Движение к цели

Ромов Дмитрий
2. Цеховик
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Цеховик. Книга 2. Движение к цели

На границе империй. Том 8

INDIGO
12. Фортуна дама переменчивая
Фантастика:
космическая фантастика
попаданцы
5.00
рейтинг книги
На границе империй. Том 8

Лекарь Империи 9

Карелин Сергей Витальевич
9. Лекарь Империи
Фантастика:
городское фэнтези
аниме
боевая фантастика
5.00
рейтинг книги
Лекарь Империи 9