$szTitle = "Qt 4.6: Реентерабельность и потокобезопасность"; include "../_header46x.inc"; ?>
Главная · Все классы · Все функции · Обзоры |
[Предыдущая: Синхронизация потоков] [Поддержка потоков в Qt] [Следующая: Потоки и объекты QObjects]
Везде в документации термины реентерабельность и потокобезопасность используются для обозначения классов и функций для указания того, как они могут быть использованы в многопоточных приложениях:
Таким образом, потокобезопасная функция всегда реентерабельна, но реентерабельная функция не всегда потокобезопасна.
В более широком смысле, класс называется реентерабельным, если его функции-члены могут быть безопасно вызваны из нескольких потоков, пока каждый поток использует свой отдельный экземпляр класса. Класс является потокобезопасным, если его функции-члены могут быть безопасно вызваны из нескольких потоков, даже если все потоки используют один и тот же экземпляр класса.
Классы C++ часто реентерабельны просто потому, что они имеют доступ только к данным своих членов. Любой поток может вызвать функцию-член экземпляра реентерабельного класса, в то время как ни один другой поток не может вызвать функцию-член того же самого экземпляра класса в тоже самое время. Например, нижеуказанный класс Counter является реентерабельным:
class Counter { public: Counter() { n = 0; } void increment() { ++n; } void decrement() { --n; } int value() const { return n; } private: int n; };
Данный класс не является потокобезопасным, поскольку если несколько потоков попытаются изменить член данных n, результат будет не определен. Это так, потому что операторы ++ и -- не всегда атомарны. В действительности, они обычно расширяются до трех машинных инструкций:
Потоки A и B одновременно могут загрузить старое значение переменной, увеличить ее значение в регистре и сохранить значение переменной в памяти, но переменная будет увеличена только однажды!
Поток A должен выполнить шаги 1, 2, 3 без прерывания (атомарно) прежде, чем поток B сможет выполнить те же шаги; или наоборот. Самый легкий способ создания потокобезопасного класса состоит в том, чтобы защитить весь доступ к членам данных с помощью QMutex:
class Counter { public: Counter() { n = 0; } void increment() { QMutexLocker locker(&mutex); ++n; } void decrement() { QMutexLocker locker(&mutex); --n; } int value() const { QMutexLocker locker(&mutex); return n; } private: mutable QMutex mutex; int n; };
Класс QMutexLocker автоматически запирает мьютекс в своем конструкторе и отпирает его в деструкторе, вызываемом при завершении функции. Запирание мьютекса гарантирует, что обращения из разных потоков будут упорядочены. Член данных mutex объявлен как mutable, потому что позволяет запереть и отпереть мьютекс в функции value(), которая является константной.
Большинство классов Qt реентерабельны, но не потокобезопасны, поскольку такая реализация потребовала бы дополнительных издержек на многократные блокировки и разблокировки QMutex. Например, QString реентерабелен, но не потокобезопасен. Вы можете смело обращаться к различным экземплярам класса QString из нескольких потоков одновременно, но вы не можете спокойно получить доступ к одному и тому же экземпляру QString из нескольких потоков одновременно (если вы самостоятельно не обеспечиваете защиту от доступа с помощью QMutex).
Некоторые классы и функции Qt потокобезопасны. Это, главным образом, связанные с потоками классы (например, QMutex) и фундаментальные функции (например, QCoreApplication::postEvent()).
Замечание: Классы Qt документируются как потокобезопасные, только если они предназначены для работы в многопоточных приложениях.
Замечание: Терминология в многопоточной области еще не полностью стандартизована. POSIX использует несколько отличающиеся определения реентерабельности и потокобезопасности для своих API C. При использовании других объектно-ориентированных библиотек классов C++ совместно с Qt убедитесь, что их определения понятны.
[Предыдущая: Синхронизация потоков] [Поддержка потоков в Qt] [Следующая: Потоки и объекты QObjects]
Авторские права © 2010 Nokia Corporation и/или её дочерние компании | Торговые марки | Qt 4.6.4 |