|
[Previous: Synchronizing Threads]
[Thread Support in Qt]
[Next: Threads and QObjects]
Реентерабельность и потокобезопасность
Throughout the documentation, the terms reentrant and thread-safe are used to mark classes and functions to indicate how they can be used in multithread applications:
- A thread-safe function can be called simultaneously from multiple threads, even when the invocations use shared data, because all references to the shared data are serialized.
- A reentrant function can also be called simultaneously from multiple threads, but only if each invocation uses its own data.
Hence, a thread-safe function is always reentrant, but a reentrant function is not always thread-safe.
By extension, a class is said to be reentrant if its member functions can be called safely from multiple threads, as long as each thread uses a different instance of the class. The class is thread-safe if its member functions can be called safely from multiple threads, even if all the threads use the same instance of the class.
C++ classes are often reentrant, simply because they only access their own member data. Any thread can call a member function on an instance of a reentrant class, as long as no other thread can call a member function on the same instance of the class at the same time. For example, the Counter class below is reentrant:
class Counter
{
public:
Counter() { n = 0; }
void increment() { ++n; }
void decrement() { --n; }
int value() const { return n; }
private:
int n;
};
Данный класс не является потокобезопасным, поскольку если несколько потоков попытаются изменить член данных n, результат будет неопределен. This is because the ++ and -- operators aren't always atomic. В действительности, они обычно расширяются до трех машинных инструкций:
- Загрузка значения переменной в регистр.
- Увеличение или уменьшение значения регистра.
- Сохранение значения регистра обратно в основную память.
Потоки 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(), которая является константной.
Many Qt classes are reentrant, but they are not made thread-safe, because making them thread-safe would incur the extra overhead of repeatedly locking and unlocking a QMutex. For example, QString is reentrant but not thread-safe. You can safely access different instances of QString from multiple threads simultaneously, but you can't safely access the same instance of QString from multiple threads simultaneously (unless you protect the accesses yourself with a QMutex).
Some Qt classes and functions are thread-safe. These are mainly the thread-related classes (e.g. QMutex) and fundamental functions (e.g. QCoreApplication::postEvent()).
Note: Qt Classes are only documented as thread-safe if they are intended to be used by multiple threads.
Note: Terminology in the multithreading domain isn't entirely standardized. POSIX uses definitions of reentrant and thread-safe that are somewhat different for its C APIs. When using other object-oriented C++ class libraries with Qt, be sure the definitions are understood.
[Previous: Synchronizing Threads]
[Thread Support in Qt]
[Next: Threads and QObjects]
| Copyright © 2010 Nokia Corporation and/or its subsidiary(-ies) |
Торговые марки |
Qt 4.6.4 |
|