前几天在博客园看到一篇文章http://www.cnblogs.com/kex1n/archive/2011/08/10/2133389.html,里面吧mutex作为一个静态成员放入一个自定义的类里。在类创生之时调用lock,类析构之时unlock。只要在关键的代码段建立一个类的实例即可,省去了手动写lock-unlock的麻烦,也降低了忘记写unlock的风险。这个办法的巧妙在于利用了静态成员:不管有多少类的实例,静态成员在内存里只有一个。
今天尝试用QT的QMutex模仿他的代码,结果碰到了问题。编译总是不通过。后来在一个国外的网站上找到了答案:在含有mutex的类的cpp文件里,必须包含
QMutex lock::mutex;这一句。
下面上代码:
lock.h和 lock.cpp这两个是包含了QMutex静态成员的类的文件
#ifndef LOCK_H
#define LOCK_H
#include <qmutex.h>
class lock
{
public:
lock();
~lock();
static QMutex mutex;
};
#endif // LOCK_H
#include "lock.h"
#include <QDebug>
QMutex lock::mutex;//这句必须存在!!!
lock::lock()
{
qDebug()<<"about to lock";
mutex.lock();
qDebug()<<"locked";
}
lock::~lock()
{
mutex.unlock();
qDebug()<<"release";
}
然后是两个竞争的线程:这2个线程其实一模一样,都属于同一个类thd
先看头文件:
#ifndef THREAD_H
#define THREAD_H
#include <QThread>
#include <QWidget>
class thd : public QThread
{
Q_OBJECT
public:
explicit thd(QWidget *, QObject *parent = 0);
~thd();
QWidget * m_p;
signals:
public slots:
protected:
void run();
};
#endif // THREAD_H
然后是cpp:
#include "thread.h"
#include "lock.h"
#include "mainwindow.h"
#include <QDebug>
thd::thd(QWidget * p, QObject *parent) : QThread(parent)
{
m_p = p;
}
thd::~thd()
{
if(isRunning())
terminate();
}
void thd::run()
{
volatile lock locker;
qDebug()<<"thread output = "<<currentThreadId();
MainWindow * p = (MainWindow *)m_p;
p->vPrintId();
}
最后是包含这两个线程的主窗体,双击它,就会启动这两个线程:
先看头文件:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QMouseEvent>
#include "thread.h"
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
void vPrintId();
thd * m_pTh1;
thd * m_pTh2;
protected:
void mouseDoubleClickEvent(QMouseEvent *);
};
#endif // MAINWINDOW_H
在看cpp:
#include "mainwindow.h"
#include <QThread>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
m_pTh1 = new thd(this);
m_pTh2 = new thd(this);
}
MainWindow::~MainWindow()
{
delete m_pTh1;
delete m_pTh2;
}
void MainWindow::vPrintId()
{
qDebug()<<"window output = "<<QThread::currentThreadId()<<"\n";
}
void MainWindow::mouseDoubleClickEvent(QMouseEvent *e)
{
m_pTh1->start();
m_pTh2->start();
}
启动后,发现程序顺序输出如下:
显然,一个线程被锁住,另一个就必须等待,说明线程很好的同步了。
最后一点要说明。其实这个静态变量也可以拿到lock.cpp的文件开头,而不必成为lock类的成员。起到的效果应该是一样的。