1 // Copyright (C) 2001-2003
2 // William E. Kempf
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6
7 #define BOOST_THREAD_VERSION 2
8
9 #include <boost/thread/mutex.hpp>
10 #include <boost/thread/condition.hpp>
11 #include <boost/thread/thread_only.hpp>
12 #include <boost/thread/xtime.hpp>
13 #include <iostream>
14 #include <time.h>
15
16 namespace
17 {
18 boost::mutex iomx;
19 } // namespace
20
21 class canteen
22 {
23 public:
canteen()24 canteen() : m_chickens(0) { }
25
get(int id)26 void get(int id)
27 {
28 boost::unique_lock<boost::mutex> lock(m_mutex);
29 while (m_chickens == 0)
30 {
31 {
32 boost::unique_lock<boost::mutex> lk(iomx);
33 std::cout << "(" << clock() << ") Phil" << id <<
34 ": wot, no chickens? I'll WAIT ..." << std::endl;
35 }
36 m_condition.wait(lock);
37 }
38 {
39 boost::unique_lock<boost::mutex> lk(iomx);
40 std::cout << "(" << clock() << ") Phil" << id <<
41 ": those chickens look good ... one please ..." << std::endl;
42 }
43 m_chickens--;
44 }
put(int value)45 void put(int value)
46 {
47 boost::unique_lock<boost::mutex> lock(m_mutex);
48 {
49 boost::unique_lock<boost::mutex> lk(iomx);
50 std::cout << "(" << clock()
51 << ") Chef: ouch ... make room ... this dish is "
52 << "very hot ..." << std::endl;
53 }
54 boost::xtime xt;
55 boost::xtime_get(&xt, boost::TIME_UTC_);
56 xt.sec += 3;
57 boost::thread::sleep(xt);
58 m_chickens += value;
59 {
60 boost::unique_lock<boost::mutex> lk(iomx);
61 std::cout << "(" << clock() <<
62 ") Chef: more chickens ... " << m_chickens <<
63 " now available ... NOTIFYING ..." << std::endl;
64 }
65 m_condition.notify_all();
66 }
67
68 private:
69 boost::mutex m_mutex;
70 boost::condition m_condition;
71 int m_chickens;
72 };
73
74 canteen g_canteen;
75
chef()76 void chef()
77 {
78 const int chickens = 4;
79 {
80 boost::unique_lock<boost::mutex> lock(iomx);
81 std::cout << "(" << clock() << ") Chef: starting ..." << std::endl;
82 }
83 for (;;)
84 {
85 {
86 boost::unique_lock<boost::mutex> lock(iomx);
87 std::cout << "(" << clock() << ") Chef: cooking ..." << std::endl;
88 }
89 boost::xtime xt;
90 boost::xtime_get(&xt, boost::TIME_UTC_);
91 xt.sec += 2;
92 boost::thread::sleep(xt);
93 {
94 boost::unique_lock<boost::mutex> lock(iomx);
95 std::cout << "(" << clock() << ") Chef: " << chickens
96 << " chickens, ready-to-go ..." << std::endl;
97 }
98 g_canteen.put(chickens);
99 }
100 }
101
102 struct phil
103 {
philphil104 phil(int id) : m_id(id) { }
runphil105 void run() {
106 {
107 boost::unique_lock<boost::mutex> lock(iomx);
108 std::cout << "(" << clock() << ") Phil" << m_id
109 << ": starting ..." << std::endl;
110 }
111 for (;;)
112 {
113 if (m_id > 0)
114 {
115 boost::xtime xt;
116 boost::xtime_get(&xt, boost::TIME_UTC_);
117 xt.sec += 3;
118 boost::thread::sleep(xt);
119 }
120 {
121 boost::unique_lock<boost::mutex> lk(iomx);
122 std::cout << "(" << clock() << ") Phil" << m_id
123 << ": gotta eat ..." << std::endl;
124 }
125 g_canteen.get(m_id);
126 {
127 boost::unique_lock<boost::mutex> lk(iomx);
128 std::cout << "(" << clock() << ") Phil" << m_id
129 << ": mmm ... that's good ..." << std::endl;
130 }
131 }
132 }
do_threadphil133 static void do_thread(void* param) {
134 static_cast<phil*>(param)->run();
135 }
136
137 int m_id;
138 };
139
140 struct thread_adapt
141 {
thread_adaptthread_adapt142 thread_adapt(void (*func)(void*), void* param)
143 : _func(func), _param(param)
144 {
145 }
operator ()thread_adapt146 int operator()() const
147 {
148 _func(_param);
149 return 0;
150 }
151
152 void (*_func)(void*);
153 void* _param;
154 };
155
156 class thread_adapter
157 {
158 public:
thread_adapter(void (* func)(void *),void * param)159 thread_adapter(void (*func)(void*), void* param)
160 : _func(func), _param(param)
161 {
162 }
operator ()() const163 void operator()() const { _func(_param); }
164 private:
165 void (*_func)(void*);
166 void* _param;
167 };
168
main()169 int main()
170 {
171 boost::thread thrd_chef(&chef);
172 phil p[] = { phil(0), phil(1), phil(2), phil(3), phil(4) };
173 boost::thread thrd_phil0(thread_adapter(&phil::do_thread, &p[0]));
174 boost::thread thrd_phil1(thread_adapter(&phil::do_thread, &p[1]));
175 boost::thread thrd_phil2(thread_adapter(&phil::do_thread, &p[2]));
176 boost::thread thrd_phil3(thread_adapter(&phil::do_thread, &p[3]));
177 boost::thread thrd_phil4(thread_adapter(&phil::do_thread, &p[4]));
178
179 thrd_chef.join();
180 thrd_phil0.join();
181 thrd_phil1.join();
182 thrd_phil2.join();
183 thrd_phil3.join();
184 thrd_phil4.join();
185
186 return 0;
187 }
188