1610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov/* 2610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov This file is part of ThreadSanitizer, a dynamic data race detector. 3610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 4610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov Copyright (C) 2008-2009 Google Inc 5610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov opensource@google.com 6610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 7610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov This program is free software; you can redistribute it and/or 8610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov modify it under the terms of the GNU General Public License as 9610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov published by the Free Software Foundation; either version 2 of the 10610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov License, or (at your option) any later version. 11610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 12610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov This program is distributed in the hope that it will be useful, but 13610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov WITHOUT ANY WARRANTY; without even the implied warranty of 14610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov General Public License for more details. 16610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 17610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov You should have received a copy of the GNU General Public License 18610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov along with this program; if not, write to the Free Software 19610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 20610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 02111-1307, USA. 21610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 22610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov The GNU General Public License is contained in the file COPYING. 23610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov*/ 24610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 25610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// Author: Konstantin Serebryany <opensource@google.com> 26610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// 27610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// Here we define a few simple classes that wrap threading primitives. 28610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// 29610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// We need this to create unit tests for ThreadSanitizer (or similar tools) 30610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// that will work with different threading frameworks. 31610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// 32610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// Note, that some of the methods defined here are annotated with 33610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// ANNOTATE_* macros defined in dynamic_annotations.h. 34610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// 35610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// DISCLAIMER: the classes defined in this header file 36610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// are NOT intended for general use -- only for unit tests. 37610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 38610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#ifndef THREAD_WRAPPERS_H 39610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#define THREAD_WRAPPERS_H 40610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 41610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#include <assert.h> 42610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#include <limits.h> // INT_MAX 43610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#include <queue> 44610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#include <stdio.h> 45610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#include <string> 46610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#include <time.h> 47610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 48610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#include "dynamic_annotations.h" 49610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 50610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovusing namespace std; 51610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 52610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#ifdef NDEBUG 53610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov# error "Pleeease, do not define NDEBUG" 54610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#endif 55610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 56610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#ifdef WIN32 57610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov# define CHECK(x) do { if (!(x)) { \ 58610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov fprintf(stderr, "Assertion failed: %s (%s:%d) %s\n", \ 59610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov __FUNCTION__, __FILE__, __LINE__, #x); \ 60610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov exit(1); }} while (0) 61610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#else 62610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov# define CHECK assert 63610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#endif 64610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 65610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov/// Just a boolean condition. Used by Mutex::LockWhen and similar. 66610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovclass Condition { 67610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov public: 68610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov typedef bool (*func_t)(void*); 69610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 70610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov template <typename T> 71610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov Condition(bool (*func)(T*), T* arg) 72610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov : func_(reinterpret_cast<func_t>(func)), arg_(arg) {} 73610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 74610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov Condition(bool (*func)()) 75610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov : func_(reinterpret_cast<func_t>(func)), arg_(NULL) {} 76610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 77610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov bool Eval() { return func_(arg_); } 78610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov private: 79610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov func_t func_; 80610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov void *arg_; 81610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov}; 82610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 83610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// Define platform-specific types, constant and functions {{{1 84610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovstatic int AtomicIncrement(volatile int *value, int increment); 85610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovstatic int GetTimeInMs(); 86610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 87610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovclass CondVar; 88610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovclass MyThread; 89610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovclass Mutex; 90610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov//}}} 91610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 92610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// Include platform-specific header with declaraions. 93610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#ifndef WIN32 94610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// Include pthread primitives (Linux, Mac) 95610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#include "thread_wrappers_pthread.h" 96610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#else 97610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// Include Windows primitives 98610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#include "thread_wrappers_win.h" 99610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#endif 100610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 101610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// Define cross-platform types synchronization primitives {{{1 102610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov/// Just a message queue. 103610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovclass ProducerConsumerQueue { 104610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov public: 105610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov ProducerConsumerQueue(int unused) { 106610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov //ANNOTATE_PCQ_CREATE(this); 107610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov } 108610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov ~ProducerConsumerQueue() { 109610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov CHECK(q_.empty()); 110610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov //ANNOTATE_PCQ_DESTROY(this); 111610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov } 112610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 113610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov // Put. 114610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov void Put(void *item) { 115610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov mu_.Lock(); 116610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov q_.push(item); 117610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov ANNOTATE_CONDVAR_SIGNAL(&mu_); // LockWhen in Get() 118610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov //ANNOTATE_PCQ_PUT(this); 119610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov mu_.Unlock(); 120610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov } 121610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 122610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov // Get. 123610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov // Blocks if the queue is empty. 124610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov void *Get() { 125610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov mu_.LockWhen(Condition(IsQueueNotEmpty, &q_)); 126610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov void * item; 127610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov bool ok = TryGetInternal(&item); 128610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov CHECK(ok); 129610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov mu_.Unlock(); 130610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov return item; 131610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov } 132610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 133610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov // If queue is not empty, 134610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov // remove an element from queue, put it into *res and return true. 135610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov // Otherwise return false. 136610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov bool TryGet(void **res) { 137610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov mu_.Lock(); 138610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov bool ok = TryGetInternal(res); 139610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov mu_.Unlock(); 140610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov return ok; 141610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov } 142610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 143610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov private: 144610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov Mutex mu_; 145610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov std::queue<void*> q_; // protected by mu_ 146610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 147610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov // Requires mu_ 148610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov bool TryGetInternal(void ** item_ptr) { 149610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov if (q_.empty()) 150610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov return false; 151610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov *item_ptr = q_.front(); 152610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov q_.pop(); 153610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov //ANNOTATE_PCQ_GET(this); 154610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov return true; 155610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov } 156610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 157610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov static bool IsQueueNotEmpty(std::queue<void*> * queue) { 158610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov return !queue->empty(); 159610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov } 160610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov}; 161610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 162610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov/// Function pointer with zero, one or two parameters. 163610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovstruct Closure { 164610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov typedef void (*F0)(); 165610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov typedef void (*F1)(void *arg1); 166610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov typedef void (*F2)(void *arg1, void *arg2); 167610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov int n_params; 168610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov void *f; 169610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov void *param1; 170610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov void *param2; 171610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 172610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov void Execute() { 173610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov if (n_params == 0) { 174610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov (F0(f))(); 175610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov } else if (n_params == 1) { 176610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov (F1(f))(param1); 177610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov } else { 178610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov CHECK(n_params == 2); 179610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov (F2(f))(param1, param2); 180610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov } 181610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov delete this; 182610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov } 183610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov}; 184610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 185610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovstatic Closure *NewCallback(void (*f)()) { 186610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov Closure *res = new Closure; 187610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov res->n_params = 0; 188610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov res->f = (void*)(f); 189610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov res->param1 = NULL; 190610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov res->param2 = NULL; 191610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov return res; 192610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov} 193610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 194610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovtemplate <class P1> 195610969f87667a485b9207086b3ff475bab909f95Evgeniy StepanovClosure *NewCallback(void (*f)(P1), P1 p1) { 196610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov CHECK(sizeof(P1) <= sizeof(void*)); 197610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov Closure *res = new Closure; 198610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov res->n_params = 1; 199610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov res->f = (void*)(f); 200610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov res->param1 = (void*)(intptr_t)p1; 201610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov res->param2 = NULL; 202610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov return res; 203610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov} 204610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 205610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovtemplate <class P1, class P2> 206610969f87667a485b9207086b3ff475bab909f95Evgeniy StepanovClosure *NewCallback(void (*f)(P1, P2), P1 p1, P2 p2) { 207610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov CHECK(sizeof(P1) <= sizeof(void*)); 208610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov CHECK(sizeof(P2) <= sizeof(void*)); 209610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov Closure *res = new Closure; 210610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov res->n_params = 2; 211610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov res->f = (void*)(f); 212610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov res->param1 = (void*)p1; 213610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov res->param2 = (void*)p2; 214610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov return res; 215610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov} 216610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 217610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov/*! A thread pool that uses ProducerConsumerQueue. 218610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov Usage: 219610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov { 220610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov ThreadPool pool(n_workers); 221610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov pool.StartWorkers(); 222610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov pool.Add(NewCallback(func_with_no_args)); 223610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov pool.Add(NewCallback(func_with_one_arg, arg)); 224610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov pool.Add(NewCallback(func_with_two_args, arg1, arg2)); 225610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov ... // more calls to pool.Add() 226610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 227610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov // the ~ThreadPool() is called: we wait workers to finish 228610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov // and then join all threads in the pool. 229610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov } 230610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov*/ 231610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovclass ThreadPool { 232610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov public: 233610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov //! Create n_threads threads, but do not start. 234610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov explicit ThreadPool(int n_threads) 235610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov : queue_(INT_MAX) { 236610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov for (int i = 0; i < n_threads; i++) { 237610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov MyThread *thread = new MyThread(&ThreadPool::Worker, this); 238610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov workers_.push_back(thread); 239610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov } 240610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov } 241610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 242610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov //! Start all threads. 243610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov void StartWorkers() { 244610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov for (size_t i = 0; i < workers_.size(); i++) { 245610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov workers_[i]->Start(); 246610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov } 247610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov } 248610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 249610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov //! Add a closure. 250610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov void Add(Closure *closure) { 251610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov queue_.Put(closure); 252610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov } 253610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 254610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov int num_threads() { return workers_.size();} 255610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 256610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov //! Wait workers to finish, then join all threads. 257610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov ~ThreadPool() { 258610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov for (size_t i = 0; i < workers_.size(); i++) { 259610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov Add(NULL); 260610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov } 261610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov for (size_t i = 0; i < workers_.size(); i++) { 262610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov workers_[i]->Join(); 263610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov delete workers_[i]; 264610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov } 265610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov } 266610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov private: 267610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov std::vector<MyThread*> workers_; 268610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov ProducerConsumerQueue queue_; 269610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 270610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov static void *Worker(void *p) { 271610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov ThreadPool *pool = reinterpret_cast<ThreadPool*>(p); 272610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov while (true) { 273610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov Closure *closure = reinterpret_cast<Closure*>(pool->queue_.Get()); 274610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov if(closure == NULL) { 275610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov return NULL; 276610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov } 277610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov closure->Execute(); 278610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov } 279610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov } 280610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov}; 281610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 282610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovclass MutexLock { // Scoped Mutex Locker/Unlocker 283610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov public: 284610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov MutexLock(Mutex *mu) 285610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov : mu_(mu) { 286610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov mu_->Lock(); 287610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov } 288610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov ~MutexLock() { 289610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov mu_->Unlock(); 290610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov } 291610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov private: 292610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov Mutex *mu_; 293610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov}; 294610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 295610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovclass BlockingCounter { 296610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov public: 297610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov explicit BlockingCounter(int initial_count) : 298610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov count_(initial_count) {} 299610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov bool DecrementCount() { 300610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov MutexLock lock(&mu_); 301610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov count_--; 302610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov return count_ == 0; 303610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov } 304610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov void Wait() { 305610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov mu_.LockWhen(Condition(&IsZero, &count_)); 306610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov mu_.Unlock(); 307610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov } 308610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov private: 309610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov static bool IsZero(int *arg) { return *arg == 0; } 310610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov Mutex mu_; 311610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov int count_; 312610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov}; 313610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 314610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov//}}} 315610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov 316610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#endif // THREAD_WRAPPERS_H 317610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// vim:shiftwidth=2:softtabstop=2:expandtab:foldmethod=marker 318