zoukankan      html  css  js  c++  java
  • Qt多线程编程总结(二)——QMutex

    QMutex类提供的是线程之间的访问顺序化。

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

    [cpp] view plain copy
     
    1. void someMethod()  
    2. {  
    3.    qDebug("Hello");  
    4.    qDebug("World");  
    5. }  

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

      Hello
      Hello
      World
      World
      

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

    [cpp] view plain copy
     
    1. QMutex mutex;  
    2.   
    3. void someMethod()  
    4. {  
    5.    mutex.lock();  
    6.    qDebug("Hello");  
    7.    qDebug("World");  
    8.    mutex.unlock();  
    9. }  

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

    [cpp] view plain copy
     
    1. void someMethod()  
    2. {  
    3.    synchronized {  
    4.      qDebug("Hello");  
    5.      qDebug("World");  
    6.    }  
    7. }  

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

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

    实验部分:

    情形一:

    [cpp] view plain copy
     
    1. #include <QtCore/QCoreApplication>  
    2. #include <Qthread>  
    3. #include <QTextStream>  
    4. class MyThreadA : public QThread {    
    5. public:      
    6. virtual void run();    
    7. };    
    8. class MyThreadB: public QThread {    
    9. public:      
    10. virtual void run();    
    11. };  
    12. int number=6;  
    13. void MyThreadA::run(){    
    14. number *= 5;  
    15. number /= 4;  
    16. }    
    17. void MyThreadB::run(){  
    18. number *= 3;  
    19. number /= 2;  
    20. }   
    21. int main(int argc, char *argv[])  
    22. {     
    23. QCoreApplication app(argc, argv);  
    24. MyThreadA a;    
    25. MyThreadB b;    
    26. a.run();  
    27. b.run();  
    28.  a.terminate();  
    29. b.terminate();  
    30. QTextStream out(stdout);  
    31. out<<number;  
    32. return app.exec();  
    33. }   

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

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

    情形二:

    [cpp] view plain copy
     
    1. #include <QtCore/QCoreApplication>  
    2. #include <Qthread>  
    3. #include <QTextStream>  
    4. class MyThreadA : public QThread {    
    5. public:      
    6. virtual void run();    
    7. };    
    8. class MyThreadB: public QThread {    
    9. public:      
    10. virtual void run();    
    11. };  
    12. int number=6;  
    13. void MyThreadA::run(){    
    14. number *= 5;  
    15. sleep(1);  
    16. number /= 4;  
    17. }    
    18. void MyThreadB::run(){  
    19. number *= 3;  
    20. sleep(1);  
    21. number /= 2;  
    22. }   
    23. int main(int argc, char *argv[])  
    24. {     
    25. QCoreApplication app(argc, argv);  
    26. MyThreadA a;    
    27. MyThreadB b;    
    28. a.start();  
    29. b.start();    
    30. a.wait();    
    31. b.wait();   
    32. QTextStream out(stdout);  
    33. out<<number;  
    34. return app.exec();  
    35. }   

    运行结果:

    number=11;

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

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

    [cpp] view plain copy
     
    1. bool QThread::wait(unsigned long time)  
    2. {  
    3.     Q_D(QThread);  
    4.     QMutexLocker locker(&d->mutex);   
    5.     if (d->id == GetCurrentThreadId()) {  
    6.         qWarning("QThread::wait: Thread tried to wait on itself");     //当是自身时,直接返回false  
    7.         return false;  
    8.     }  
    9.     if (d->finished || !d->running) //与这个线程对象关联的线程已经结束执行(例如从run函数返回)。如果线程结束返回真值。如果线程还没有开始也返回真值。  
    10.         return true;  
    11.     ++d->waiters;  
    12.     locker.mutex()->unlock();  
    13.   
    14.   
    15.     bool ret = false;  
    16.     switch (WaitForSingleObject(d->handle, time)) {   //调用win的对象处理函数  
    17.     case WAIT_OBJECT_0:    //核心对象被激活,等待成功  
    18.         ret = true;  
    19.         break;  
    20.     case WAIT_FAILED:  
    21.         qErrnoWarning("QThread::wait: Thread wait failure");       
    22.         break;  
    23.     case WAIT_ABANDONED:  
    24.     case WAIT_TIMEOUT:  
    25.     default:  
    26.         break;  
    27.     }  
    28.     locker.mutex()->lock();  
    29.     --d->waiters;  
    30.     if (ret && !d->finished) {                                  //虽然响应成功,但关联对象未结束执行  
    31.         // thread was terminated by someone else  
    32.         d->terminated = true;              
    33.         QThreadPrivate::finish(this, false);  
    34.     }  
    35.     if (d->finished && !d->waiters) {    //关联对象执行结束,并且等待数为零时,关闭句柄。  
    36.         CloseHandle(d->handle);  
    37.         d->handle = 0;  
    38.     }  
    39.     return ret;  
    40. }  



    情形三:(Mutex 作用)

    [cpp] view plain copy
     
    1. #include <QtCore/QCoreApplication>  
    2. #include <Qthread>  
    3. #include <QTextStream>  
    4. #include <QMutex>  
    5. class MyThreadA : public QThread {    
    6. public:      
    7. virtual void run();    
    8. };    
    9. class MyThreadB: public QThread {    
    10. public:      
    11. virtual void run();    
    12. };  
    13. QMutex mutex;  
    14. int number=6;  
    15. void MyThreadA::run(){    
    16. mutex.lock();  
    17. number *= 5;  
    18. sleep(1);  
    19. number /= 4;  
    20. mutex.unlock();  
    21. }    
    22. void MyThreadB::run(){  
    23. mutex.lock();  
    24. number *= 3;  
    25. sleep(1);  
    26. number /= 2;  
    27. mutex.unlock();  
    28. }   
    29. int main(int argc, char *argv[])  
    30. {     
    31. QCoreApplication app(argc, argv);  
    32. MyThreadA a;    
    33. MyThreadB b;    
    34. a.start();  
    35. b.start();    
    36. a.wait();    
    37. b.wait();    
    38. QTextStream out(stdout);  
    39. out<<number;  
    40. return app.exec();  
    41. }   


    运行结果:

    number=10;

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

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

    且不能添上sleep()函数,否则提示 "A mutex must be unlocked in the same thread that locked it."的运行错误。

    http://blog.csdn.net/mznewfacer/article/details/6966752

  • 相关阅读:
    Alpha 冲刺 (9/10)
    Alpha 冲刺 (8/10)
    Alpha 冲刺 (7/10)
    Alpha 冲刺 (6/10)
    Alpha 冲刺 (5/10)
    团队现场编程实战(抽奖系统)
    Alpha 冲刺 (4/10)
    斗地主
    解方程
    货币系统
  • 原文地址:https://www.cnblogs.com/findumars/p/5599430.html
Copyright © 2011-2022 走看看