[12] | 1 | <?xml version="1.0" encoding="utf-8"?> |
---|
| 2 | <!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" |
---|
| 3 | "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [ |
---|
| 4 | <!ENTITY % threads.entities SYSTEM "entities.xml"> |
---|
| 5 | %threads.entities; |
---|
| 6 | ]> |
---|
| 7 | <section id="threads.faq" last-revision="$Date: 2004/07/17 04:33:59 $"> |
---|
| 8 | <title>Frequently Asked Questions</title> |
---|
| 9 | <qandaset> |
---|
| 10 | <qandaentry> |
---|
| 11 | <question> |
---|
| 12 | <para>Are lock objects <link |
---|
| 13 | linkend="threads.glossary.thread-safe">thread safe</link>?</para> |
---|
| 14 | </question> |
---|
| 15 | <answer> |
---|
| 16 | <para><emphasis role="bold">No!</emphasis> Lock objects are not meant to |
---|
| 17 | be shared between threads. They are meant to be short-lived objects |
---|
| 18 | created on automatic storage within a code block. Any other usage is |
---|
| 19 | just likely to lead to errors and won't really be of actual benefit anyway. |
---|
| 20 | Share <link linkend="threads.concepts.mutexes">Mutexes</link>, not |
---|
| 21 | Locks. For more information see the <link |
---|
| 22 | linkend="threads.rationale.locks">rationale</link> behind the |
---|
| 23 | design for lock objects.</para> |
---|
| 24 | </answer> |
---|
| 25 | </qandaentry> |
---|
| 26 | <qandaentry> |
---|
| 27 | <question> |
---|
| 28 | <para>Why was &Boost.Threads; modeled after (specific library |
---|
| 29 | name)?</para> |
---|
| 30 | </question> |
---|
| 31 | <answer> |
---|
| 32 | <para>It wasn't. &Boost.Threads; was designed from scratch. Extensive |
---|
| 33 | design discussions involved numerous people representing a wide range of |
---|
| 34 | experience across many platforms. To ensure portability, the initial |
---|
| 35 | implements were done in parallel using POSIX Threads and the Win32 |
---|
| 36 | threading API. But the &Boost.Threads; design is very much in the spirit |
---|
| 37 | of C++, and thus doesn't model such C based APIs.</para> |
---|
| 38 | </answer> |
---|
| 39 | </qandaentry> |
---|
| 40 | <qandaentry> |
---|
| 41 | <question> |
---|
| 42 | <para>Why wasn't &Boost.Threads; modeled after (specific library |
---|
| 43 | name)?</para> |
---|
| 44 | </question> |
---|
| 45 | <answer> |
---|
| 46 | <para>Existing C++ libraries either seemed dangerous (often failing to |
---|
| 47 | take advantage of prior art to reduce errors) or had excessive |
---|
| 48 | dependencies on library components unrelated to threading. Existing C |
---|
| 49 | libraries couldn't meet our C++ requirements, and were also missing |
---|
| 50 | certain features. For instance, the WIN32 thread API lacks condition |
---|
| 51 | variables, even though these are critical for the important Monitor |
---|
| 52 | pattern &cite.SchmidtStalRohnertBuschmann;.</para> |
---|
| 53 | </answer> |
---|
| 54 | </qandaentry> |
---|
| 55 | <qandaentry> |
---|
| 56 | <question> |
---|
| 57 | <para>Why do <link linkend="threads.concepts.mutexes">Mutexes</link> |
---|
| 58 | have noncopyable semantics?</para> |
---|
| 59 | </question> |
---|
| 60 | <answer> |
---|
| 61 | <para>To ensure that <link |
---|
| 62 | linkend="threads.glossary.deadlock">deadlocks</link> don't occur. The |
---|
| 63 | only logical form of copy would be to use some sort of shallow copy |
---|
| 64 | semantics in which multiple mutex objects could refer to the same mutex |
---|
| 65 | state. This means that if ObjA has a mutex object as part of its state |
---|
| 66 | and ObjB is copy constructed from it, then when ObjB::foo() locks the |
---|
| 67 | mutex it has effectively locked ObjA as well. This behavior can result |
---|
| 68 | in deadlock. Other copy semantics result in similar problems (if you |
---|
| 69 | think you can prove this to be wrong then supply us with an alternative |
---|
| 70 | and we'll reconsider).</para> |
---|
| 71 | </answer> |
---|
| 72 | </qandaentry> |
---|
| 73 | <qandaentry> |
---|
| 74 | <question> |
---|
| 75 | <para>How can you prevent <link |
---|
| 76 | linkend="threads.glossary.deadlock">deadlock</link> from occurring when |
---|
| 77 | a thread must lock multiple mutexes?</para> |
---|
| 78 | </question> |
---|
| 79 | <answer> |
---|
| 80 | <para>Always lock them in the same order. One easy way of doing this is |
---|
| 81 | to use each mutex's address to determine the order in which they are |
---|
| 82 | locked. A future &Boost.Threads; concept may wrap this pattern up in a |
---|
| 83 | reusable class.</para> |
---|
| 84 | </answer> |
---|
| 85 | </qandaentry> |
---|
| 86 | <qandaentry> |
---|
| 87 | <question> |
---|
| 88 | <para>Don't noncopyable <link |
---|
| 89 | linkend="threads.concepts.mutexes">Mutex</link> semantics mean that a |
---|
| 90 | class with a mutex member will be noncopyable as well?</para> |
---|
| 91 | </question> |
---|
| 92 | <answer> |
---|
| 93 | <para>No, but what it does mean is that the compiler can't generate a |
---|
| 94 | copy constructor and assignment operator, so they will have to be coded |
---|
| 95 | explicitly. This is a <emphasis role="bold">good thing</emphasis>, |
---|
| 96 | however, since the compiler generated operations would not be <link |
---|
| 97 | linkend="threads.glossary.thread-safe">thread-safe</link>. The following |
---|
| 98 | is a simple example of a class with copyable semantics and internal |
---|
| 99 | synchronization through a mutex member.</para> |
---|
| 100 | <programlisting> |
---|
| 101 | class counter |
---|
| 102 | { |
---|
| 103 | public: |
---|
| 104 | // Doesn't need synchronization since there can be no references to *this |
---|
| 105 | // until after it's constructed! |
---|
| 106 | explicit counter(int initial_value) |
---|
| 107 | : m_value(initial_value) |
---|
| 108 | { |
---|
| 109 | } |
---|
| 110 | // We only need to synchronize other for the same reason we don't have to |
---|
| 111 | // synchronize on construction! |
---|
| 112 | counter(const counter& other) |
---|
| 113 | { |
---|
| 114 | boost::mutex::scoped_lock scoped_lock(other.m_mutex); |
---|
| 115 | m_value = other.m_value; |
---|
| 116 | } |
---|
| 117 | // For assignment we need to synchronize both objects! |
---|
| 118 | const counter& operator=(const counter& other) |
---|
| 119 | { |
---|
| 120 | if (this == &other) |
---|
| 121 | return *this; |
---|
| 122 | boost::mutex::scoped_lock lock1(&m_mutex < &other.m_mutex ? m_mutex : other.m_mutex); |
---|
| 123 | boost::mutex::scoped_lock lock2(&m_mutex > &other.m_mutex ? m_mutex : other.m_mutex); |
---|
| 124 | m_value = other.m_value; |
---|
| 125 | return *this; |
---|
| 126 | } |
---|
| 127 | int value() const |
---|
| 128 | { |
---|
| 129 | boost::mutex::scoped_lock scoped_lock(m_mutex); |
---|
| 130 | return m_value; |
---|
| 131 | } |
---|
| 132 | int increment() |
---|
| 133 | { |
---|
| 134 | boost::mutex::scoped_lock scoped_lock(m_mutex); |
---|
| 135 | return ++m_value; |
---|
| 136 | } |
---|
| 137 | private: |
---|
| 138 | mutable boost::mutex m_mutex; |
---|
| 139 | int m_value; |
---|
| 140 | }; |
---|
| 141 | </programlisting> |
---|
| 142 | </answer> |
---|
| 143 | </qandaentry> |
---|
| 144 | <qandaentry> |
---|
| 145 | <question> |
---|
| 146 | <para>How can you lock a <link |
---|
| 147 | linkend="threads.concepts.mutexes">Mutex</link> member in a const member |
---|
| 148 | function, in order to implement the Monitor Pattern?</para> |
---|
| 149 | </question> |
---|
| 150 | <answer> |
---|
| 151 | <para>The Monitor Pattern &cite.SchmidtStalRohnertBuschmann; mutex |
---|
| 152 | should simply be declared as mutable. See the example code above. The |
---|
| 153 | internal state of mutex types could have been made mutable, with all |
---|
| 154 | lock calls made via const functions, but this does a poor job of |
---|
| 155 | documenting the actual semantics (and in fact would be incorrect since |
---|
| 156 | the logical state of a locked mutex clearly differs from the logical |
---|
| 157 | state of an unlocked mutex). Declaring a mutex member as mutable clearly |
---|
| 158 | documents the intended semantics.</para> |
---|
| 159 | </answer> |
---|
| 160 | </qandaentry> |
---|
| 161 | <qandaentry> |
---|
| 162 | <question> |
---|
| 163 | <para>Why supply <classname>boost::condition</classname> variables rather than |
---|
| 164 | event variables?</para> |
---|
| 165 | </question> |
---|
| 166 | <answer> |
---|
| 167 | <para>Condition variables result in user code much less prone to <link |
---|
| 168 | linkend="threads.glossary.race-condition">race conditions</link> than |
---|
| 169 | event variables. See <xref linkend="threads.rationale.events" /> |
---|
| 170 | for analysis. Also see &cite.Hoare74; and &cite.SchmidtStalRohnertBuschmann;. |
---|
| 171 | </para> |
---|
| 172 | </answer> |
---|
| 173 | </qandaentry> |
---|
| 174 | <qandaentry> |
---|
| 175 | <question> |
---|
| 176 | <para>Why isn't thread cancellation or termination provided?</para> |
---|
| 177 | </question> |
---|
| 178 | <answer> |
---|
| 179 | <para>There's a valid need for thread termination, so at some point |
---|
| 180 | &Boost.Threads; probably will include it, but only after we can find a |
---|
| 181 | truly safe (and portable) mechanism for this concept.</para> |
---|
| 182 | </answer> |
---|
| 183 | </qandaentry> |
---|
| 184 | <qandaentry> |
---|
| 185 | <question> |
---|
| 186 | <para>Is it safe for threads to share automatic storage duration (stack) |
---|
| 187 | objects via pointers or references?</para> |
---|
| 188 | </question> |
---|
| 189 | <answer> |
---|
| 190 | <para>Only if you can guarantee that the lifetime of the stack object |
---|
| 191 | will not end while other threads might still access the object. Thus the |
---|
| 192 | safest practice is to avoid sharing stack objects, particularly in |
---|
| 193 | designs where threads are created and destroyed dynamically. Restrict |
---|
| 194 | sharing of stack objects to simple designs with very clear and |
---|
| 195 | unchanging function and thread lifetimes. (Suggested by Darryl |
---|
| 196 | Green).</para> |
---|
| 197 | </answer> |
---|
| 198 | </qandaentry> |
---|
| 199 | <qandaentry> |
---|
| 200 | <question> |
---|
| 201 | <para>Why has class semaphore disappeared?</para> |
---|
| 202 | </question> |
---|
| 203 | <answer> |
---|
| 204 | <para>Semaphore was removed as too error prone. The same effect can be |
---|
| 205 | achieved with greater safety by the combination of a mutex and a |
---|
| 206 | condition variable.</para> |
---|
| 207 | </answer> |
---|
| 208 | </qandaentry> |
---|
| 209 | </qandaset> |
---|
| 210 | </section> |
---|