source: trunk/doc/src/examples/semaphores.qdoc@ 109

Last change on this file since 109 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 7.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the documentation of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42/*!
43 \example threads/semaphores
44 \title Semaphores Example
45
46 The Semaphores example shows how to use QSemaphore to control
47 access to a circular buffer shared by a producer thread and a
48 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 Semaphores make it possible to have a higher level of concurrency
56 than mutexes. If accesses to the buffer were guarded by a QMutex,
57 the consumer thread couldn't access the buffer at the same time
58 as the producer thread. Yet, there is no harm in having both
59 threads working on \e{different parts} of the buffer at the same
60 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 semaphores that
65 protect it are global variables.
66
67 An alternative to using QSemaphore to solve the producer-consumer
68 problem is to use QWaitCondition and QMutex. This is what the
69 \l{threads/waitconditions}{Wait Conditions} example does.
70
71 \section1 Global Variables
72
73 Let's start by reviewing the circular buffer and the associated
74 semaphores:
75
76 \snippet examples/threads/semaphores/semaphores.cpp 0
77
78 \c DataSize is the amout 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
85 semaphores. The \c freeBytes semaphore controls the "free" area
86 of the buffer (the area that the producer hasn't filled with data
87 yet or that the consumer has already read). The \c usedBytes
88 semaphore controls the "used" area of the buffer (the area that
89 the producer has filled but that the consumer hasn't read yet).
90
91 Together, the semaphores ensure that the producer is never more
92 than \c BufferSize bytes ahead of the consumer, and that the
93 consumer never reads data that the producer hasn't generated yet.
94
95 The \c freeBytes semaphore is initialized with \c BufferSize,
96 because initially the entire buffer is empty. The \c usedBytes
97 semaphore is initialized to 0 (the default value if none is
98 specified).
99
100 \section1 Producer Class
101
102 Let's review the code for the \c Producer class:
103
104 \snippet examples/threads/semaphores/semaphores.cpp 1
105 \snippet examples/threads/semaphores/semaphores.cpp 2
106
107 The producer generates \c DataSize bytes of data. Before it
108 writes a byte to the circular buffer, it must acquire a "free"
109 byte using the \c freeBytes semaphore. The QSemaphore::acquire()
110 call might block if the consumer hasn't kept up the pace with the
111 producer.
112
113 At the end, the producer releases a byte using the \c usedBytes
114 semaphore. The "free" byte has successfully been transformed into
115 a "used" byte, ready to be read by the consumer.
116
117 \section1 Consumer Class
118
119 Let's now turn to the \c Consumer class:
120
121 \snippet examples/threads/semaphores/semaphores.cpp 3
122 \snippet examples/threads/semaphores/semaphores.cpp 4
123
124 The code is very similar to the producer, except that this time
125 we acquire a "used" byte and release a "free" byte, instead of
126 the opposite.
127
128 \section1 The main() Function
129
130 In \c main(), we create the two threads and call QThread::wait()
131 to ensure that both threads get time to finish before we exit:
132
133 \snippet examples/threads/semaphores/semaphores.cpp 5
134 \snippet examples/threads/semaphores/semaphores.cpp 6
135
136 So what happens when we run the program? Initially, the producer
137 thread is the only one that can do anything; the consumer is
138 blocked waiting for the \c usedBytes semaphore to be released (its
139 initial \l{QSemaphore::available()}{available()} count is 0).
140 Once the producer has put one byte in the buffer,
141 \c{freeBytes.available()} is \c BufferSize - 1 and
142 \c{usedBytes.available()} is 1. At that point, two things can
143 happen: Either the consumer thread takes over and reads that
144 byte, or the consumer gets to produce a second byte.
145
146 The producer-consumer model presented in this example makes it
147 possible to write highly concurrent multithreaded applications.
148 On a multiprocessor machine, the program is potentially up to
149 twice as fast as the equivalent mutex-based program, since the
150 two threads can be active at the same time on different parts of
151 the buffer.
152
153 Be aware though that these benefits aren't always realized.
154 Acquiring and releasing a QSemaphore has a cost. In practice, it
155 would probably be worthwhile to divide the buffer into chunks and
156 to operate on chunks instead of individual bytes. The buffer size
157 is also a parameter that must be selected carefully, based on
158 experimentation.
159*/
Note: See TracBrowser for help on using the repository browser.