|
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/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 */ |