QT 中的生产者和消费者信号量

本文介绍了Qt中的两种同步机制:QWaitCondition和QSemaphore,并通过具体示例展示了如何使用这两种机制来实现多线程间的同步操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

为了高效实现环形缓冲区的生产者和消费者的异步通信操作。我们需要用Qt中的QWaitCondition 或者QSemaphore

本文介绍一下Qt中关于这两个类的例子。(Qt4.7)

QWaitCondition介绍


QWaitCondition Class Reference

The QWaitCondition class provides a condition variable for synchronizing threads.

  1. #include <QWaitCondition>

Note: All functions in this class are thread-safe.

Detailed Description

The QWaitCondition class provides a condition variable for synchronizing threads.

QWaitCondition allows a thread to tell other threads that some sort of condition has been met. One or many threads can block waiting for a QWaitCondition to set a condition with wakeOne() or wakeAll(). Use wakeOne() to wake one randomly selected condition or wakeAll() to wake them all.

For example, let's suppose that we have three tasks that should be performed whenever the user presses a key. Each task could be split into a thread, each of which would have a run() body like this:

  1. forever   {
  2.     mutex. lock ( ) ;
  3.     keyPressed. wait ( &mutex ) ;
  4.     do_something ( ) ;
  5.     mutex. unlock ( ) ;
  6. }

Here, the keyPressed variable is a global variable of type QWaitCondition.

A fourth thread would read key presses and wake the other three threads up every time it receives one, like this:

  1. forever   {
  2.      getchar ( ) ;
  3.     keyPressed. wakeAll ( ) ;
  4. }

The order in which the three threads are woken up is undefined. Also, if some of the threads are still in do_something() when the key is pressed, they won't be woken up (since they're not waiting on the condition variable) and so the task will not be performed for that key press. This issue can be solved using a counter and a QMutex to guard it. For example, here's the new code for the worker threads:

  1. forever   {
  2.     mutex. lock ( ) ;
  3.     keyPressed. wait ( &mutex ) ;
  4.      ++count ;
  5.     mutex. unlock ( ) ;
  6.  
  7.     do_something ( ) ;
  8.  
  9.     mutex. lock ( ) ;
  10.      --count ;
  11.     mutex. unlock ( ) ;
  12. }

Here's the code for the fourth thread:

  1. forever   {
  2.      getchar ( ) ;
  3.  
  4.     mutex. lock ( ) ;
  5.      // Sleep until there are no busy worker threads
  6.      while  (count  >  0 )   {
  7.         mutex. unlock ( ) ;
  8.         sleep ( 1 ) ;
  9.         mutex. lock ( ) ;
  10.      }
  11.     keyPressed. wakeAll ( ) ;
  12.     mutex. unlock ( ) ;
  13. }

The mutex is necessary because the results of two threads attempting to change the value of the same variable simultaneously are unpredictable.

Wait conditions are a powerful thread synchronization primitive. The Wait Conditions example shows how to use QWaitCondition as an alternative to QSemaphore for controlling access to a circular buffer shared by a producer thread and a consumer thread.

See also QMutexQSemaphoreQThread, and Wait Conditions Example.

Public Functions

Toggle details QWaitCondition

QWaitCondition()

Toggle details QWaitCondition

~QWaitCondition()

Toggle details boolQWaitCondition

wait(QMutex *mutex , unsigned longtime=ULONG_MAX...)

Toggle details boolQWaitCondition

wait(QReadWriteLock *readWriteLock , unsigned longtime=ULONG_MAX...)

Toggle details voidQWaitCondition

wakeAll()

Toggle details voidQWaitCondition

wakeOne()

QWaitCondition完整例子:

  1. #include <QtCore>
  2.  
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5.  
  6. const   int   DataSize   =   100000 ;
  7. const   int   BufferSize   =   8192 ;
  8. char  buffer [ BufferSize ] ;
  9.  
  10. QWaitCondition  bufferNotEmpty ;
  11. QWaitCondition  bufferNotFull ;
  12. QMutex  mutex ;
  13. int  numUsedBytes  =   0 ;
  14.  
  15. class   Producer   :   public   QThread
  16.   {
  17. public :
  18.      void  run ( ) ;
  19. } ;
  20.  
  21. void   Producer :: run ( )
  22.   {
  23.     qsrand ( QTime ( 0 , 0 , 0 ) . secsTo ( QTime :: currentTime ( ) ) ) ;
  24.  
  25.      for   ( int  i  =   0 ;  i  <   DataSize ;   ++ i )    {
  26.         mutex . lock ( ) ;
  27.          if   ( numUsedBytes  ==   BufferSize )
  28.             bufferNotFull . wait ( & mutex ) ;
  29.         mutex . unlock ( ) ;
  30.  
  31.         buffer [ %   BufferSize ]   =   "ACGT" [ ( int ) qrand ( )   %   4 ] ;
  32.  
  33.         mutex . lock ( ) ;
  34.          ++ numUsedBytes ;
  35.         bufferNotEmpty . wakeAll ( ) ;
  36.         mutex . unlock ( ) ;
  37.      }
  38. }
  39.  
  40. class   Consumer   :   public   QThread
  41.   {
  42. public :
  43.      void  run ( ) ;
  44. } ;
  45.  
  46. void   Consumer :: run ( )
  47.   {
  48.      for   ( int  i  =   0 ;  i  <   DataSize ;   ++ i )    {
  49.         mutex . lock ( ) ;
  50.          if   ( numUsedBytes  ==   0 )
  51.             bufferNotEmpty . wait ( & mutex ) ;
  52.         mutex . unlock ( ) ;
  53.  
  54.          fprintf ( stderr ,   "%c" ,  buffer [ %   BufferSize ] ) ;
  55.  
  56.         mutex . lock ( ) ;
  57.          -- numUsedBytes ;
  58.         bufferNotFull . wakeAll ( ) ;
  59.         mutex . unlock ( ) ;
  60.      }
  61.      fprintf ( stderr ,   "\n" ) ;
  62. }
  63.  
  64. int  main ( int  argc ,   char   * argv [ ] )
  65.   {
  66.      QCoreApplication  app ( argc ,  argv ) ;
  67.      Producer  producer ;
  68.      Consumer  consumer ;
  69.     producer . start ( ) ;
  70.     consumer . start ( ) ;
  71.     producer . wait ( ) ;
  72.     consumer . wait ( ) ;
  73.      return   0 ;
  74. }

QSemaphore介绍


QSemaphore Class Reference

The QSemaphore class provides a general counting semaphore.

  1. #include <QSemaphore>

Note: All functions in this class are thread-safe.

Detailed Description

The QSemaphore class provides a general counting semaphore.

A semaphore is a generalization of a mutex. While a mutex can only be locked once, it's possible to acquire a semaphore multiple times. Semaphores are typically used to protect a certain number of identical resources.

Semaphores support two fundamental operations, acquire() and release():

  • acquire(n) tries to acquire n resources. If there aren't that many resources available, the call will block until this is the case.
  • release(n) releases n resources.

There's also a tryAcquire() function that returns immediately if it cannot acquire the resources, and an available() function that returns the number of available resources at any time.

Example:

  1. QSemaphore sem ( 5 ) ;       // sem.available() == 5
  2.  
  3. sem. acquire ( 3 ) ;          // sem.available() == 2
  4. sem. acquire ( 2 ) ;          // sem.available() == 0
  5. sem. release ( 5 ) ;          // sem.available() == 5
  6. sem. release ( 5 ) ;          // sem.available() == 10
  7.  
  8. sem. tryAcquire ( 1 ) ;       // sem.available() == 9, returns true
  9. sem. tryAcquire ( 250 ) ;     // sem.available() == 9, returns false

A typical application of semaphores is for controlling access to a circular buffer shared by a producer thread and a consumer thread. TheSemaphores example shows how to use QSemaphore to solve that problem.

A non-computing example of a semaphore would be dining at a restaurant. A semaphore is initialized with the number of chairs in the restaurant. As people arrive, they want a seat. As seats are filled, available() is decremented. As people leave, the available() is incremented, allowing more people to enter. If a party of 10 people want to be seated, but there are only 9 seats, those 10 people will wait, but a party of 4 people would be seated (taking the available seats to 5, making the party of 10 people wait longer).

See also QMutexQWaitConditionQThread, and Semaphores Example.

Public Functions

Toggle details QSemaphore

QSemaphore(intn=0)

Toggle details QSemaphore

~QSemaphore()

Toggle details voidQSemaphore

acquire(intn=1)

Toggle details intQSemaphore

available()const

Toggle details voidQSemaphore

release(intn=1)

Toggle details boolQSemaphore

tryAcquire(intn=1)

Toggle details boolQSemaphore

tryAcquire(intn , inttimeout)

    You may use the documentation under the terms of the  GNU Free Documentation License version 1.3, as published by the Free Software Foundation. Alternatively, you may use the documentation in accordance with the terms contained in a written agreement between you and Digia.
    QSemaphore完整例子:

    1. #include <QtCore>
    2.  
    3. #include <stdio.h>
    4. #include <stdlib.h>
    5.  
    6. const   int   DataSize   =   100000 ;
    7. const   int   BufferSize   =   8192 ;
    8. char  buffer [ BufferSize ] ;
    9.  
    10. QSemaphore  freeBytes ( BufferSize ) ;
    11. QSemaphore  usedBytes ;
    12.  
    13. class   Producer   :   public   QThread
    14.   {
    15. public :
    16.      void  run ( ) ;
    17. } ;
    18.  
    19. void   Producer :: run ( )
    20.   {
    21.     qsrand ( QTime ( 0 , 0 , 0 ) . secsTo ( QTime :: currentTime ( ) ) ) ;
    22.      for   ( int  i  =   0 ;  i  <   DataSize ;   ++ i )    {
    23.         freeBytes . acquire ( ) ;
    24.         buffer [ %   BufferSize ]   =   "ACGT" [ ( int ) qrand ( )   %   4 ] ;
    25.         usedBytes . release ( ) ;
    26.      }
    27. }
    28.  
    29. class   Consumer   :   public   QThread
    30.   {
    31. public :
    32.      void  run ( ) ;
    33. } ;
    34.  
    35. void   Consumer :: run ( )
    36.   {
    37.      for   ( int  i  =   0 ;  i  <   DataSize ;   ++ i )    {
    38.         usedBytes . acquire ( ) ;
    39.          fprintf ( stderr ,   "%c" ,  buffer [ %   BufferSize ] ) ;
    40.         freeBytes . release ( ) ;
    41.      }
    42.      fprintf ( stderr ,   "\n" ) ;
    43. }
    44.  
    45. int  main ( int  argc ,   char   * argv [ ] )
    46.   {
    47.      QCoreApplication  app ( argc ,  argv ) ;
    48.      Producer  producer ;
    49.      Consumer  consumer ;
    50.     producer . start ( ) ;
    51.     consumer . start ( ) ;
    52.     producer . wait ( ) ;
    53.     consumer . wait ( ) ;
    54.      return   0 ;
    55. }


    FROM: http://blog.163.com/qimo601@126/blog/static/1582209320121118112828662/


    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值