您的位置:首页 > 编程语言 > Qt开发

Qt多线程编程总结(二)——QMutex

2013-08-10 19:08 183 查看
QMutex类提供的是线程之间的访问顺序化。

QMutex的目的是保护一个对象、数据结构或者代码段,所以同一时间只有一个线程可以访问它。(在Java术语中,它和同步关键字“synchronized”很相似)。例如,这里有一个方法打印给用户两条消息:

[cpp] view
plaincopy

void someMethod()  

{  

   qDebug("Hello");  

   qDebug("World");  

}  

如果同时在两个线程中调用这个方法,结果的顺序将是:

Hello
Hello
World
World


如果你使用了一个互斥量:

[cpp] view
plaincopy

QMutex mutex;  

  

void someMethod()  

{  

   mutex.lock();  

   qDebug("Hello");  

   qDebug("World");  

   mutex.unlock();  

}  

用Java的术语,这段代码应该是:

[cpp] view
plaincopy

void someMethod()  

{  

   synchronized {  

     qDebug("Hello");  

     qDebug("World");  

   }  

}  

然后同一时间只有一个线程可以运行someMethod并且消息的顺序也一直是正确的。当然,这只是一个很简单的例子,但是它适用于任何需要按特定频率发生的情况。

但你在一个线程中调用lock(),其它线程将会在同一地点试图调用lock()来阻塞,知道这个线程调用unlock()之后其它线程才会获得这个锁。lock()的一种非阻塞选择是tryLock()。

实验部分:

情形一:

[cpp] view
plaincopy

#include <QtCore/QCoreApplication>  

#include <Qthread>  

#include <QTextStream>  

class MyThreadA : public QThread {    

public:      

virtual void run();    

};    

class MyThreadB: public QThread {    

public:      

virtual void run();    

};  

int number=6;  

void MyThreadA::run(){    

number *= 5;  

number /= 4;  

}    

void MyThreadB::run(){  

number *= 3;  

number /= 2;  

}   

int main(int argc, char *argv[])  

{     

QCoreApplication app(argc, argv);  

MyThreadA a;    

MyThreadB b;    

a.run();  

b.run();  

 a.terminate();  

b.terminate();  

QTextStream out(stdout);  

out<<number;  

return app.exec();  

}   

上述代码,很简单,写了两个线程,覆盖了QThread的纯虚函数run(),这两个重构的run方法都是对全局变量number的操作,

主函数中顺序调用这两个方法,a.run()执行后number为7,b.run()执行后为10。

情形二:

[cpp] view
plaincopy

#include <QtCore/QCoreApplication>  

#include <Qthread>  

#include <QTextStream>  

class MyThreadA : public QThread {    

public:      

virtual void run();    

};    

class MyThreadB: public QThread {    

public:      

virtual void run();    

};  

int number=6;  

void MyThreadA::run(){    

number *= 5;  

sleep(1);  

number /= 4;  

}    

void MyThreadB::run(){  

number *= 3;  

sleep(1);  

number /= 2;  

}   

int main(int argc, char *argv[])  

{     

QCoreApplication app(argc, argv);  

MyThreadA a;    

MyThreadB b;    

a.start();  

b.start();    

a.wait();    

b.wait();   

QTextStream out(stdout);  

out<<number;  

return app.exec();  

}   

运行结果:

number=11;

利用QThread的方法start()同是开启两个线程,值得注意的是wait()函数,不能等待自己,这个是用来多个线程交互的,所以不能当sleep()用。这个函数是在主线程中被调用的时候阻塞了主线程。如果想在外部让子线程暂停,最好的办法是在子线程中设置一个标志,在主线程中更改这个标志,并在子线程的run函数中判断,通过调用其保护函数sleep()来达到暂停的目的了。

查看源代码,即可有清楚的概念:

[cpp] view
plaincopy

bool QThread::wait(unsigned long time)  

{  

    Q_D(QThread);  

    QMutexLocker locker(&d->mutex);   

    if (d->id == GetCurrentThreadId()) {  

        qWarning("QThread::wait: Thread tried to wait on itself");     //当是自身时,直接返回false  

        return false;  

    }  

    if (d->finished || !d->running) //与这个线程对象关联的线程已经结束执行(例如从run函数返回)。如果线程结束返回真值。如果线程还没有开始也返回真值。  

        return true;  

    ++d->waiters;  

    locker.mutex()->unlock();  

  

  

    bool ret = false;  

    switch (WaitForSingleObject(d->handle, time)) {   //调用win的对象处理函数  

    case WAIT_OBJECT_0:    //核心对象被激活,等待成功  

        ret = true;  

        break;  

    case WAIT_FAILED:  

        qErrnoWarning("QThread::wait: Thread wait failure");       

        break;  

    case WAIT_ABANDONED:  

    case WAIT_TIMEOUT:  

    default:  

        break;  

    }  

    locker.mutex()->lock();  

    --d->waiters;  

    if (ret && !d->finished) {                                  //虽然响应成功,但关联对象未结束执行  

        // thread was terminated by someone else  

        d->terminated = true;              

        QThreadPrivate::finish(this, false);  

    }  

    if (d->finished && !d->waiters) {    //关联对象执行结束,并且等待数为零时,关闭句柄。  

        CloseHandle(d->handle);  

        d->handle = 0;  

    }  

    return ret;  

}  

情形三:(Mutex 作用)

[cpp] view
plaincopy

#include <QtCore/QCoreApplication>  

#include <Qthread>  

#include <QTextStream>  

#include <QMutex>  

class MyThreadA : public QThread {    

public:      

virtual void run();    

};    

class MyThreadB: public QThread {    

public:      

virtual void run();    

};  

QMutex mutex;  

int number=6;  

void MyThreadA::run(){    

mutex.lock();  

number *= 5;  

sleep(1);  

number /= 4;  

mutex.unlock();  

}    

void MyThreadB::run(){  

mutex.lock();  

number *= 3;  

sleep(1);  

number /= 2;  

mutex.unlock();  

}   

int main(int argc, char *argv[])  

{     

QCoreApplication app(argc, argv);  

MyThreadA a;    

MyThreadB b;    

a.start();  

b.start();    

a.wait();    

b.wait();    

QTextStream out(stdout);  

out<<number;  

return app.exec();  

}   

运行结果:

number=10;

通过实验结果可以看出,QMutex保护了全局变量,同一时间只有一个线程可以访问它。

只得一提的是tryLock()的使用,若以上代码换为mutex.tryLock();那么执行结果可能为11,因为是试图锁定互斥量。如果锁被得到,这个函数返回真。如果另一个进程已经锁定了这个互斥量,这个函数返回假,而不是一直等到这个锁可用为止。

且不能添上sleep()函数,否则提示 "A mutex must be unlocked in the same thread that locked it."的运行错误。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: