A platform for high-performance distributed tool and library development written in C++. It can be deployed in two different cluster modes: standalone or distributed. API for v0.5.0, released on June 13, 2018.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
PDBWorkerQueue.h
Go to the documentation of this file.
1 /*****************************************************************************
2  * *
3  * Copyright 2018 Rice University *
4  * *
5  * Licensed under the Apache License, Version 2.0 (the "License"); *
6  * you may not use this file except in compliance with the License. *
7  * You may obtain a copy of the License at *
8  * *
9  * http://www.apache.org/licenses/LICENSE-2.0 *
10  * *
11  * Unless required by applicable law or agreed to in writing, software *
12  * distributed under the License is distributed on an "AS IS" BASIS, *
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
14  * See the License for the specific language governing permissions and *
15  * limitations under the License. *
16  * *
17  *****************************************************************************/
18 /*
19  * File: PDBWorkerQueue.h
20  * Author: Chris
21  *
22  * Created on September 25, 2015, 5:13 PM
23  */
24 
25 #ifndef PDBWORKERQUEUE_H
26 #define PDBWORKERQUEUE_H
27 
28 
29 #include <memory>
30 
31 #include "PDBLogger.h"
32 #include "PDBWorker.h"
33 #include <pthread.h>
34 #include <set>
35 #include <vector>
36 
37 // this encapsulates a queue of workers
38 
39 namespace pdb {
40 
41 // create a smart pointer for PDBWorkerQueue objects
43 typedef shared_ptr<PDBWorkerQueue> PDBWorkerQueuePtr;
44 
45 class PDBWorker;
46 typedef shared_ptr<PDBWorker> PDBWorkerPtr;
47 
49 public:
50  // the standard allocation block size in a worker is 64KB
51  static const size_t defaultAllocatorBlockSize = (1024 * 64);
52 
53  // create a worker queue that has the specified number of workers... output is written
54  // to the specified logger
55  PDBWorkerQueue(PDBLoggerPtr myLogger, int numWorkers);
56 
57  // destroy the queue... if there are any outstanding workers, this will not complete
58  // until they have all finished their work and been destroyed
60 
61  // this gets a worker thread, encapsulated within an instance of the PDBWorker class
62  // If all of the threds that are managed by this particular PDBWorkerQueue are busy
63  // doing work, then this call will block. If there are no wokers at all in this
64  // PDBWorkerQueue object (not even any busy ones) this returns a nullptr
65  //
66  // Once a worker finishes its work (that is, it finishes executing a PDBWork object)
67  // it is automatically recycled (returned to the queue). The only way that it is
68  // not recycled is if worker.needToDieWhenDone () returns true. In this case, the
69  // thread inside of the worker is allowed to die.
70  //
71  // IMPORTANT: if you get a PDBWorker object via this call, you MUST use it via a call
72  // to execute, or else the thread inside of it becomes a zombie, and will wait forever!
73  //
74  // note that this is the only interface method that can be run asynchrously, outside of
75  // the main thread. It is assumed that all other calls to the interface methods run on
76  // the same thread!!
78 
79  // adds another worker to the queue... give the worker the range where its call stack
80  // should exist
81  void addAnotherWorker(void* stackStart, void* stackEnd);
82 
83  // notify all of the workers that are currently assigned (and working) regarding some
84  // event. This basically means that worker.soundBuzzer (withMe) is called for all
85  // workers. If, after the call to worker.soundBuzzer (withMe), it is the case that
86  // worker.needToDieWhenDone () returns true, then the worker is immediately (and
87  // automatically) replaced with a new one. In this way, a call to notifyAllWorkers
88  // can be used to have a bunch of threads die in response to some event. For example,
89  // if a server goes down, then all of the threads that are interacting with it can
90  // be notified via a call to notifyAllWorkers; they can then decide to kill themselves
91  // and safely be abandoned by the system, to be reclaimed later.
92  void notifyAllWorkers(PDBAlarm withMe);
93 
94  // this is how a thread gets into the queue... it calls "enter"... don't call this
95  // method unless you want to be captured and used as a worker!!
96  void enter();
97 
98  // gets the logger
100 
101 private:
102  // these are the workers that are unassigned
103  vector<PDBWorkerPtr> waiting;
104 
105  // the protecting mutex, and the assocaited signal variable
106  pthread_mutex_t waitingMutex;
107  pthread_cond_t waitingSignal;
108 
109  // these are all of the workers that are currently doing work
110  set<PDBWorkerPtr> working;
111 
112  // the list of all of the threads
113  vector<pthread_t> threads;
114 
115  // the protecting mutex
116  pthread_mutex_t workingMutex;
117 
118  // keeps track of how many workers we have created
119  int numOut;
120 
121  // true when the destructor is active
123 
124  // the logger to write to
126 
127  // a pointer to the original location for the call stacks for all of the worker threads
128  // we need this so that we can free the memory at shutdown
130 };
131 }
132 
133 #endif /* PDBWORKERQUEUE_H */
PDBWorkerPtr getWorker()
void notifyAllWorkers(PDBAlarm withMe)
PDBLoggerPtr myLogger
static const size_t defaultAllocatorBlockSize
void * stackEnd
vector< PDBWorkerPtr > waiting
set< PDBWorkerPtr > working
pthread_mutex_t waitingMutex
void addAnotherWorker(void *stackStart, void *stackEnd)
pthread_mutex_t workingMutex
PDBWorkerQueue(PDBLoggerPtr myLogger, int numWorkers)
shared_ptr< PDBWorkerQueue > PDBWorkerQueuePtr
shared_ptr< PDBWorker > PDBWorkerPtr
Definition: PDBWorker.h:40
PDBAlarm
Definition: PDBAlarm.h:28
std::shared_ptr< PDBLogger > PDBLoggerPtr
Definition: PDBLogger.h:40
pthread_cond_t waitingSignal
vector< pthread_t > threads
PDBLoggerPtr getLogger()