1// Copyright (C) 2003-2015 Free Software Foundation, Inc. 2// 3// This file is part of the GNU ISO C++ Library. This library is free 4// software; you can redistribute it and/or modify it under the 5// terms of the GNU General Public License as published by the 6// Free Software Foundation; either version 3, or (at your option) 7// any later version. 8 9// This library is distributed in the hope that it will be useful, 10// but WITHOUT ANY WARRANTY; without even the implied warranty of 11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12// GNU General Public License for more details. 13 14// You should have received a copy of the GNU General Public License along 15// with this library; see the file COPYING3. If not see 16// <http://www.gnu.org/licenses/>. 17 18 19#include <testsuite_performance.h> 20 21typedef int test_type; 22 23// The number of iterations to be performed. 24int iterations = 1000; 25 26// TODO - restore Stefan's comment? i don't understand it. -- fwy 27int insert_values = 128; 28 29class Lock 30{ 31public: 32 Lock() {pthread_mutex_init(&mutex, 0);} 33 ~Lock() {pthread_mutex_destroy(&mutex);} 34 35public: 36 inline pthread_mutex_t* operator&() {return &mutex;} 37 38public: 39 inline void lock() {pthread_mutex_lock(&mutex);} 40 inline void unlock() {pthread_mutex_unlock(&mutex);} 41 42private: 43 Lock(const Lock&); 44 Lock& operator=(Lock&); 45 46private: 47 pthread_mutex_t mutex; 48}; 49 50class AutoLock 51{ 52public: 53 AutoLock(Lock& _lock) 54 : lock(_lock) 55 {lock.lock();} 56 57 ~AutoLock() {lock.unlock();} 58 59private: 60 AutoLock(AutoLock&); 61 AutoLock& operator=(AutoLock&); 62 63private: 64 Lock& lock; 65}; 66 67template<typename Container> 68 class Queue 69 { 70 public: 71 Queue() {pthread_cond_init(&condition, 0);} 72 ~Queue() {pthread_cond_destroy(&condition);} 73 74 public: 75 void push_back(const typename Container::value_type& x); 76 void swap(Container& container); 77 78 private: 79 pthread_cond_t condition; 80 Lock lock; 81 Container queue; 82 }; 83 84template<typename Container> 85 void 86 Queue<Container>::push_back(const typename Container::value_type& value) 87 { 88 AutoLock auto_lock(lock); 89 const bool signal = queue.empty(); 90 queue.insert(queue.end(), value); 91 if (signal) pthread_cond_signal(&condition); 92 } 93 94template<typename Container> 95 void 96 Queue<Container>::swap(Container& container) 97 { 98 AutoLock auto_lock(lock); 99 while (queue.empty()) pthread_cond_wait(&condition, &lock); 100 queue.swap(container); 101 } 102 103class Thread 104{ 105 // NB: Make this the last data member of an object defining operator()(). 106public: 107 class Attributes 108 { 109 public: 110 Attributes(int state = PTHREAD_CREATE_JOINABLE); 111 ~Attributes() {pthread_attr_destroy(&attributes);} 112 113 public: 114 inline pthread_attr_t* operator&() {return &attributes;} 115 116 private: 117 pthread_attr_t attributes; 118 }; 119 120public: 121 Thread() {thread = pthread_self();} 122 ~Thread(); 123 124public: 125 template <typename ThreadOwner> 126 void create(ThreadOwner* owner); 127 128private: 129 pthread_t thread; 130}; 131 132Thread::Attributes::Attributes(int state) 133{ 134 pthread_attr_init(&attributes); 135 pthread_attr_setdetachstate(&attributes, state); 136} 137 138Thread::~Thread() 139{ 140 if (!pthread_equal(thread, pthread_self())) 141 pthread_join(thread, 0); 142} 143 144template<typename ThreadOwner> 145 void* 146 create_thread(void* _this) 147 { 148 ThreadOwner* owner = static_cast<ThreadOwner*>(_this); 149 (*owner)(); 150 return 0; 151 } 152 153template<typename ThreadOwner> 154 void 155 Thread::create(ThreadOwner* owner) 156 { 157 Thread::Attributes attributes; 158 pthread_create(&thread, &attributes, create_thread<ThreadOwner>, owner); 159 } 160 161template<typename Container> 162 class Consumer 163 { 164 public: 165 Consumer(Queue<Container>& _queue) 166 : queue(_queue) 167 {thread.create(this);} 168 169 public: 170 void operator()(); 171 172 private: 173 Queue<Container>& queue; 174 Thread thread; 175 }; 176 177template<typename Container> 178 void 179 Consumer<Container>::operator()() 180 { 181 for (int j = insert_values * iterations; j > 0;) 182 { 183 Container container; 184 queue.swap(container); 185 j -= container.size(); 186 } 187 } 188 189template<typename TestType> 190 struct Value : public std::pair<TestType, TestType> 191 { 192 Value() 193 : std::pair<TestType, TestType>(0, 0) 194 { } 195 196 inline Value operator++() {return ++this->first, *this;} 197 inline operator TestType() const {return this->first;} 198 }; 199 200template<typename Container> 201 class ProducerConsumer : private Queue<Container> 202 { 203 public: 204 ProducerConsumer() {thread.create(this);} 205 206 public: 207 void operator()(); 208 209 private: 210 Thread thread; 211 }; 212 213template<typename Container> 214 void 215 ProducerConsumer<Container>::operator()() 216 { 217 Consumer<Container> consumer(*this); 218 Value<test_type> test_value; 219 for (int j = insert_values * iterations; j-- > 0;) 220 this->push_back(++test_value); 221 } 222 223template<typename Container, int Iter> 224 void 225 do_loop() 226 { 227 ProducerConsumer<Container> pc1; 228 ProducerConsumer<Container> pc2; 229 } 230 231int 232main() 233{ 234#ifdef TEST_T1 235#define thread_type true 236#endif 237 238 typedef __gnu_test::maps<test_type, thread_type>::type map_typelist; 239 typedef __gnu_test::sets<test_type, thread_type>::type set_typelist; 240 typedef __gnu_cxx::typelist::append<map_typelist, set_typelist>::type container_types; 241 242 typedef test_sequence<thread_type> test_type; 243 test_type test("producer_consumer_associative"); 244 __gnu_cxx::typelist::apply(test, container_types()); 245 246 return 0; 247} 248 249