doc/src/examples/waitconditions.qdoc
branchRCL_3
changeset 7 3f74d0d4af4c
equal deleted inserted replaced
6:dee5afe5301f 7:3f74d0d4af4c
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the documentation of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 /*!
       
    43     \example threads/waitconditions
       
    44     \title Wait Conditions Example
       
    45 
       
    46     The Wait Conditions example shows how to use QWaitCondition and
       
    47     QMutex to control access to a circular buffer shared by a
       
    48     producer thread and a consumer thread.
       
    49 
       
    50     The producer writes data to the buffer until it reaches the end
       
    51     of the buffer, at which point it restarts from the beginning,
       
    52     overwriting existing data. The consumer thread reads the data as
       
    53     it is produced and writes it to standard error.
       
    54 
       
    55     Wait conditions make it possible to have a higher level of
       
    56     concurrency than what is possible with mutexes alone. If accesses
       
    57     to the buffer were simply guarded by a QMutex, the consumer
       
    58     thread couldn't access the buffer at the same time as the
       
    59     producer thread. Yet, there is no harm in having both threads
       
    60     working on \e{different parts} of the buffer at the same time.
       
    61 
       
    62     The example comprises two classes: \c Producer and \c Consumer.
       
    63     Both inherit from QThread. The circular buffer used for
       
    64     communicating between these two classes and the synchronization
       
    65     tools that protect it are global variables.
       
    66 
       
    67     An alternative to using QWaitCondition and QMutex to solve the
       
    68     producer-consumer problem is to use QSemaphore. This is what the
       
    69     \l{threads/semaphores}{Semaphores} example does.
       
    70 
       
    71     \section1 Global Variables
       
    72 
       
    73     Let's start by reviewing the circular buffer and the associated
       
    74     synchronization tools:
       
    75 
       
    76     \snippet examples/threads/waitconditions/waitconditions.cpp 0
       
    77 
       
    78     \c DataSize is the amount of data that the producer will generate.
       
    79     To keep the example as simple as possible, we make it a constant.
       
    80     \c BufferSize is the size of the circular buffer. It is less than
       
    81     \c DataSize, meaning that at some point the producer will reach
       
    82     the end of the buffer and restart from the beginning.
       
    83 
       
    84     To synchronize the producer and the consumer, we need two wait
       
    85     conditions and one mutex. The \c bufferNotEmpty condition is
       
    86     signalled when the producer has generated some data, telling the
       
    87     consumer that it can start reading it. The \c bufferNotFull
       
    88     condition is signalled when the consumer has read some data,
       
    89     telling the producer that it can generate more. The \c numUsedBytes
       
    90     is the number of bytes in the buffer that contain data.
       
    91 
       
    92     Together, the wait conditions, the mutex, and the \c numUsedBytes
       
    93     counter ensure that the producer is never more than \c BufferSize
       
    94     bytes ahead of the consumer, and that the consumer never reads
       
    95     data that the consumer hasn't generated yet.
       
    96 
       
    97     \section1 Producer Class
       
    98 
       
    99     Let's review the code for the \c Producer class:
       
   100 
       
   101     \snippet examples/threads/waitconditions/waitconditions.cpp 1
       
   102     \snippet examples/threads/waitconditions/waitconditions.cpp 2
       
   103 
       
   104     The producer generates \c DataSize bytes of data. Before it
       
   105     writes a byte to the circular buffer, it must first check whether
       
   106     the buffer is full (i.e., \c numUsedBytes equals \c BufferSize).
       
   107     If the buffer is full, the thread waits on the \c bufferNotFull
       
   108     condition.
       
   109 
       
   110     At the end, the producer increments \c numUsedBytes and signalls
       
   111     that the condition \c bufferNotEmpty is true, since \c
       
   112     numUsedBytes is necessarily greater than 0.
       
   113 
       
   114     We guard all accesses to the \c numUsedBytes variable with a
       
   115     mutex. In addition, the QWaitCondition::wait() function accepts a
       
   116     mutex as its argument. This mutex is unlocked before the thread
       
   117     is put to sleep and locked when the thread wakes up. Furthermore,
       
   118     the transition from the locked state to the wait state is atomic,
       
   119     to prevent race conditions from occurring.
       
   120 
       
   121     \section1 Consumer Class
       
   122 
       
   123     Let's turn to the \c Consumer class:
       
   124 
       
   125     \snippet examples/threads/waitconditions/waitconditions.cpp 3
       
   126     \snippet examples/threads/waitconditions/waitconditions.cpp 4
       
   127 
       
   128     The code is very similar to the producer. Before we read the
       
   129     byte, we check whether the buffer is empty (\c numUsedBytes is 0)
       
   130     instead of whether it's full and wait on the \c bufferNotEmpty
       
   131     condition if it's empty. After we've read the byte, we decrement
       
   132     \c numUsedBytes (instead of incrementing it), and we signal the
       
   133     \c bufferNotFull condition (instead of the \c bufferNotEmpty
       
   134     condition).
       
   135 
       
   136     \section1 The main() Function
       
   137 
       
   138     In \c main(), we create the two threads and call QThread::wait()
       
   139     to ensure that both threads get time to finish before we exit:
       
   140 
       
   141     \snippet examples/threads/waitconditions/waitconditions.cpp 5
       
   142     \snippet examples/threads/waitconditions/waitconditions.cpp 6
       
   143 
       
   144     So what happens when we run the program? Initially, the producer
       
   145     thread is the only one that can do anything; the consumer is
       
   146     blocked waiting for the \c bufferNotEmpty condition to be
       
   147     signalled (\c numUsedBytes is 0). Once the producer has put one
       
   148     byte in the buffer, \c numUsedBytes is \c BufferSize - 1 and the
       
   149     \c bufferNotEmpty condition is signalled. At that point, two
       
   150     things can happen: Either the consumer thread takes over and
       
   151     reads that byte, or the consumer gets to produce a second byte.
       
   152 
       
   153     The producer-consumer model presented in this example makes it
       
   154     possible to write highly concurrent multithreaded applications.
       
   155     On a multiprocessor machine, the program is potentially up to
       
   156     twice as fast as the equivalent mutex-based program, since the
       
   157     two threads can be active at the same time on different parts of
       
   158     the buffer.
       
   159 
       
   160     Be aware though that these benefits aren't always realized.
       
   161     Locking and unlocking a QMutex has a cost. In practice, it would
       
   162     probably be worthwhile to divide the buffer into chunks and to
       
   163     operate on chunks instead of individual bytes. The buffer size is
       
   164     also a parameter that must be selected carefully, based on
       
   165     experimentation.
       
   166 */