QT多线程系统分析QThread
比赛推迟到了明天,今晚还要继续早点休息了。今天的天气突然变得特别冷,真不敢想象明天早上六点五十要在校门口集合是一个什么感觉。
好了,现在开始今天的分析,我们从QThread类开始。路径corelib/thread/thread.h。在QThread类中引用了
class QThreadData;
class QThreadPrivate;
首先该类提供了几个静态方法:
static Qt::HANDLE currentThreadId();
static QThread *currentThread();
static int idealThreadCount();
static void yieldCurrentThread();
接下来提供了线程优先级的枚举类型:
enum Priority {
IdlePriority,
LowestPriority,
LowPriority,
NormalPriority,
HighPriority,
HighestPriority,
TimeCriticalPriority,
InheritPriority
};
分别为:空闲时、最低、低、正常、高、最高、立即方式、继承父类优先级。
另一个比较有用的函数是void setStackSize(uint stackSize);如果在线程中进行递归调用,那么可以通过增加堆得大小来保证递归不会溢出。
剩下是几个函数是我们经常见到的了:
void start(Priority = InheritPriority);
void terminate();
void quit();
public:
// default argument causes thread to block indefinately
bool wait(unsigned long time = ULONG_MAX);
Q_SIGNALS:
void started();
void finished();
void terminated();
protected:
virtual void run();
int exec();
static void setTerminationEnabled(bool enabled = true);
static void sleep(unsigned long);
static void msleep(unsigned long);
static void usleep(unsigned long);
static void initialize();
static void cleanup();
friend class QCoreApplication;
friend class QThreadData;
当定义为QT_NO_THREAD时,该类将只为内部主线程使用:
class Q_CORE_EXPORT QThread : public QObject
{
public:
static Qt::HANDLE currentThreadId() { return Qt::HANDLE(currentThread()); }
static QThread* currentThread();
protected:
QThread(QThreadPrivate &dd, QObject *parent = 0);
private:
explicit QThread(QObject *parent = 0);
static QThread *instance;
friend class QCoreApplication;
friend class QThreadData;
friend class QAdoptedThread;
Q_DECLARE_PRIVATE(QThread)
};
该类的实现是全部交给了其内部类QThreadPrivate,接下来,我们分析QThreadPrivate类,该类在qthread_p.h中定义。
在该文件中,我们看到了:
class QAbstractEventDispatcher;
class QEventLoop;
这两个前向声明可以看出来,这里需要用到时间传递,下面就刚好定义了一些与事件相关的类:
class QPostEvent
{
public:
QObject *receiver;
QEvent *event;
int priority;
inline QPostEvent()
: receiver(0), event(0), priority(0)
{ }
inline QPostEvent(QObject *r, QEvent *e, int p)
: receiver(r), event(e), priority(p)
{ }
};
inline bool operator<(int priority, const QPostEvent &pe)
{
return pe.priority < priority;
}
inline bool operator<(const QPostEvent &pe, int priority)
{
return priority < pe.priority;
}
该类保存了接收类的对象指针,发送的事件指针,以及优先级信息。重载的比较运算法,用于比较优先级高低。
class QPostEventList : public QList<QPostEvent>
{
public:
// recursion == recursion count for sendPostedEvents()
int recursion;
// sendOffset == the current event to start sending
int startOffset;
// insertionOffset == set by sendPostedEvents to tell postEvent() where to start insertions
int insertionOffset;
QMutex mutex;
inline QPostEventList()
: QList<QPostEvent>(), recursion(0), startOffset(0), insertionOffset(0)
{ }
};
该类用于对QPostEvent列表的一个封装同时提供了多线程同步功能。
接下来是QThreadPrivate类的定义了:
class QThreadPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QThread)
public:
QThreadPrivate(QThreadData *d = 0);
~QThreadPrivate();
mutable QMutex mutex;
bool running;
bool finished;
bool terminated;
uint stackSize;
QThread::Priority priority;
static QThread *threadForId(int id);
#ifdef Q_OS_UNIX
pthread_t thread_id;
QWaitCondition thread_done;
static void *start(void *arg);
#if defined(Q_OS_SYMBIAN)
static void finish(void *arg, bool lockAnyway=true, bool closeNativeHandle=true);
#else
static void finish(void *);
#endif
#endif // Q_OS_UNIX
#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
HANDLE handle;
unsigned int id;
int waiters;
static unsigned int __stdcall start(void *);
static void finish(void *, bool lockAnyway=true);
#endif // Q_OS_WIN32
#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) || defined (Q_OS_SYMBIAN)
bool terminationEnabled, terminatePending;
# endif
QThreadData *data;
static void createEventDispatcher(QThreadData *data);
};
这里我们看到了创建事件分派器的代码:
void QThreadPrivate::createEventDispatcher(QThreadData *data)
{
#if !defined(QT_NO_GLIB)
if (qgetenv("QT_NO_GLIB").isEmpty()
&& qgetenv("QT_NO_THREADED_GLIB").isEmpty()
&& QEventDispatcherGlib::versionSupported())
data->eventDispatcher = new QEventDispatcherGlib;
else
#endif
#ifdef Q_OS_SYMBIAN
data->eventDispatcher = new QEventDispatcherSymbian;
#else
data->eventDispatcher = new QEventDispatcherUNIX;
#endif
data->eventDispatcher->startingUp();
}
但是这里居然没有关于Win32的类对象创建,看来需要继续寻找。
bool running;
bool finished;
bool terminated;
uint stackSize;
QThread::Priority priority;
这里定义了类的运行状态,堆得大小,优先级信息。
现在找到了问题所在,为什么刚才在createEventDispatcher中没有找到Windows的事件派送器创建,我找错了文件,在qthread_win.cpp中,我们再去看下刚才的那个函数。
void QThreadPrivate::createEventDispatcher(QThreadData *data)
{
data->eventDispatcher = new QEventDispatcherWin32;
data->eventDispatcher->startingUp();
}
这里,我们找到了我们想要的东西。
下面,我们看下start函数:
unsigned int __stdcall QThreadPrivate::start(void *arg)
{
QThread *thr = reinterpret_cast<QThread *>(arg);
QThreadData *data = QThreadData::get2(thr);
qt_create_tls();
TlsSetValue(qt_current_thread_data_tls_index, data);
QThread::setTerminationEnabled(false);
data->quitNow = false;
// ### TODO: allow the user to create a custom event dispatcher
createEventDispatcher(data);
#if !defined(QT_NO_DEBUG) && defined(Q_CC_MSVC) && !defined(Q_OS_WINCE)
// sets the name of the current thread.
QByteArray objectName = thr->objectName().toLocal8Bit();
qt_set_thread_name((HANDLE)-1,
objectName.isEmpty() ?
thr->metaObject()->className() : objectName.constData());
#endif
emit thr->started();
QThread::setTerminationEnabled(true);
thr->run();
finish(arg);
return 0;
}
在该方法的实现中,我们看到了创建事件分配器的方法,在创建过程中,不允许程序外部中断运行过程。
接下来,我们看下QThread类的方法实现:
void QThread::start(Priority priority)
{
Q_D(QThread);
QMutexLocker locker(&d->mutex);
if (d->running)
return;
d->running = true;
d->finished = false;
d->terminated = false;
/*
NOTE: we create the thread in the suspended state, set the
priority and then resume the thread.
since threads are created with normal priority by default, we
could get into a case where a thread (with priority less than
NormalPriority) tries to create a new thread (also with priority
less than NormalPriority), but the newly created thread preempts
its 'parent' and runs at normal priority.
*/
d->handle = (Qt::HANDLE) _beginthreadex(NULL, d->stackSize, QThreadPrivate::start,
this, CREATE_SUSPENDED, &(d->id));
if (!d->handle) {
qErrnoWarning(errno, "QThread::start: Failed to create thread");
d->running = false;
d->finished = true;
return;
}
int prio;
d->priority = priority;
switch (d->priority) {
case IdlePriority:
prio = THREAD_PRIORITY_IDLE;
break;
case LowestPriority:
prio = THREAD_PRIORITY_LOWEST;
break;
case LowPriority:
prio = THREAD_PRIORITY_BELOW_NORMAL;
break;
case NormalPriority:
prio = THREAD_PRIORITY_NORMAL;
break;
case HighPriority:
prio = THREAD_PRIORITY_ABOVE_NORMAL;
break;
case HighestPriority:
prio = THREAD_PRIORITY_HIGHEST;
break;
case TimeCriticalPriority:
prio = THREAD_PRIORITY_TIME_CRITICAL;
break;
case InheritPriority:
default:
prio = GetThreadPriority(GetCurrentThread());
break;
}
if (!SetThreadPriority(d->handle, prio)) {
qErrnoWarning("QThread::start: Failed to set thread priority");
}
if (ResumeThread(d->handle) == (DWORD) -1) {
qErrnoWarning("QThread::start: Failed to resume new thread");
}
}
通过该方法中的说明,我们了解到,当线程创建时,其默认权限为normal。通过_beginthreadex方法创建线程。线程创建后首先被挂起,当完成优先级的设定后,会唤醒线程。
相应的,其他几个线程的方法也是类似的操作。但是今天要休息了,只能在明天继续分析。明天再次查看QCoreAppcation类的exec()方法,看是怎么启动线程的。
2009年10月31日星期六 22:33