1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   An example that shows how to implement the monitor synchronization concept.
3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   See also http://en.wikipedia.org/wiki/Monitor_(synchronization) for more
4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   information about this concept.
5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ----------------------------------------------------------------
7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Notice that the following BSD-style license applies to this one
9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   file (monitor_example.cpp) only.  The rest of Valgrind is licensed
10ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   under the terms of the GNU General Public License, version 2,
11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   unless otherwise indicated.  See the COPYING file in the source
12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   distribution for details.
13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ----------------------------------------------------------------
15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This file is part of DRD, a heavyweight Valgrind tool for detecting
17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   errors in multithreaded programs.
18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Copyright (C) 2008-2009 Bart Van Assche. All rights reserved.
20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Redistribution and use in source and binary forms, with or without
22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   modification, are permitted provided that the following conditions
23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   are met:
24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   1. Redistributions of source code must retain the above copyright
26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      notice, this list of conditions and the following disclaimer.
27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   2. The origin of this software must not be misrepresented; you must
29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      not claim that you wrote the original software.  If you use this
30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      software in a product, an acknowledgment in the product
31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      documentation would be appreciated but is not required.
32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   3. Altered source versions must be plainly marked as such, and must
34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      not be misrepresented as being the original software.
35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   4. The name of the author may not be used to endorse or promote
37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      products derived from this software without specific prior written
38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      permission.
39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ----------------------------------------------------------------
53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Notice that the above BSD-style license applies to this one
55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   file (monitor_example.cpp) only.  The rest of Valgrind is licensed
56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   under the terms of the GNU General Public License, version 2,
57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   unless otherwise indicated.  See the COPYING file in the source
58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   distribution for details.
59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ----------------------------------------------------------------
61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define _GNU_SOURCE 1
65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "config.h"
68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <cassert>
69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <iostream>
70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <pthread.h>
71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownclass Monitor
74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownpublic:
76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  Monitor()
77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    : m_mutex()
78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    , m_cond()
79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    , m_owner()
80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    , m_recursion_count()
81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  {
82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    pthread_mutexattr_t mutexattr;
83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    pthread_mutexattr_init(&mutexattr);
84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE);
85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    pthread_mutex_init(&m_mutex, &mutexattr);
86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    pthread_mutexattr_destroy(&mutexattr);
87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    pthread_condattr_t condattr;
88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    pthread_condattr_init(&condattr);
89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(HAVE_PTHREAD_CONDATTR_SETCLOCK)
90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC);
91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    pthread_cond_init(&m_cond, &condattr);
93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    pthread_condattr_destroy(&condattr);
94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  }
95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  ~Monitor()
96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  {
97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    assert(m_recursion_count == 0);
98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    pthread_cond_destroy(&m_cond);
99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    pthread_mutex_destroy(&m_mutex);
100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  }
101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  void lock()
102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  {
103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    pthread_mutex_lock(&m_mutex);
104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    assert(m_recursion_count >= 0);
105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    if (++m_recursion_count == 1)
106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    {
107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      m_owner = pthread_self();
108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  }
110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  void unlock()
111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  {
112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    m_recursion_count--;
113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    assert(m_recursion_count >= 0);
114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    pthread_mutex_unlock(&m_mutex);
115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  }
116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  void wait()
117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  {
118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    assert(m_recursion_count == 1);
119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    assert(m_owner == pthread_self());
120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    m_recursion_count--;
121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    pthread_cond_wait(&m_cond, &m_mutex);
122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    m_recursion_count++;
123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    m_owner = pthread_self();
124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  }
125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  void signal()
126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  {
127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    assert(m_recursion_count > 0);
128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    pthread_cond_signal(&m_cond);
129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  }
130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  void broadcast_signal()
131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  {
132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    assert(m_recursion_count > 0);
133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    pthread_cond_broadcast(&m_cond);
134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  }
135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  bool is_locked_by_self()
136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  {
137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    bool result;
138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    pthread_mutex_lock(&m_mutex);
139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    result = m_recursion_count > 0 && m_owner == pthread_self();
140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    pthread_mutex_unlock(&m_mutex);
141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    return result;
142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  }
143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownprivate:
145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  Monitor(const Monitor&);
146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  Monitor& operator=(const Monitor&);
147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  pthread_mutex_t m_mutex;
149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  pthread_cond_t  m_cond;
150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  pthread_t       m_owner;
151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  int             m_recursion_count;
152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown};
153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownclass ScopedLock
156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownpublic:
158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  ScopedLock(Monitor& m)
159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    : m_monitor(m)
160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    , m_locked(false)
161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  { lock(); }
162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  ~ScopedLock()
163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  { if (m_locked) unlock(); }
164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  void lock()
165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  { assert(! m_locked); m_monitor.lock(); m_locked = true; }
166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  void unlock()
167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  { assert(m_locked); m_locked = false; m_monitor.unlock(); }
168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownprivate:
170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  ScopedLock(const ScopedLock&);
171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  ScopedLock& operator=(const ScopedLock&);
172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  Monitor& m_monitor;
174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  bool     m_locked;
175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown};
176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownclass StateVariable
179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownpublic:
181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  StateVariable()
182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    : m_state()
183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  { }
184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  int get()
185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  {
186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    ScopedLock sl(m_monitor);
187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    return m_state;
188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  }
189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  void set(const int state)
190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  {
191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    ScopedLock sl(m_monitor);
192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    m_state = state;
193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    m_monitor.signal();
194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  }
195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  void wait(const int state)
196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  {
197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    ScopedLock sl(m_monitor);
198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    while (m_state != state)
199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      m_monitor.wait();
200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  }
201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownprivate:
203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  Monitor m_monitor;
204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  int     m_state;
205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown};
206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic StateVariable s_sv;
209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void* thread_func(void*)
212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  s_sv.wait(1);
214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  s_sv.set(2);
215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  s_sv.wait(3);
216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  s_sv.set(4);
217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  return 0;
218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownint main(int, char**)
221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  pthread_t tid;
223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  pthread_create(&tid, 0, thread_func, 0);
224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  s_sv.set(1);
225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  s_sv.wait(2);
226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  s_sv.set(3);
227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  s_sv.wait(4);
228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  pthread_join(tid, 0);
229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  std::cerr << "Finished successfully.\n";
230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  return 0;
231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
232