class semaphore {
public:
semaphore(int value = 0);
void wait();
void signal();
private:
int value;
std::mutex m;
std::condition_variable_any cv;
semaphore(const semaphore& orig) = delete;
const semaphore& operator=(const semaphore& rhs) const = delete;
};
semaphore::semaphore(int value) : value(value), {}
void semaphore::wait() {
lock_guard<mutex> lg(m);
cv.wait(m, [this]{ return value > 0; });
value--;
}
void semaphore::signal() {
lock_guard<mutex> lg(m);
value++;
if (value == 1) cv.notify_all();
}
static mutex forks[kNumForks];
static semaphore numAllowed(kNumForks - 1);
static void eat(unsigned int id) {
unsigned int left = id;
unsigned int right = (id + 1) % kNumForks;
numAllowed.wait(); // atomic -- that blocks on attempt to decrement 0
forks[left].lock();
forks[right].lock();
cout << oslock << id << " starts eating om nom nom nom." << endl << osunlock;
sleep_for(getEatDuration());
cout << oslock << id << " all done eating." << endl << osunlock;
numAllowed.signal(); // atomic ++, never blocks, possibly unblocks other waiting threads
forks[left].unlock();
forks[right].unlock();
}
static const unsigned int kNumBuffers = 30;
static const unsigned int kNumCycles = 4;
static char buffer[kNumBuffers];
static semaphore emptyBuffers(kNumBuffers);
static semaphore fullBuffers(0);
static void writer() {
cout << oslock << "Writer: ready to write." << endl << osunlock;
for (unsigned int i = 0; i < kNumCycles * kNumBuffers; i++) {
char ch = prepareData();
emptyBuffers.wait(); // don't try to write to a slot unless you know it's empty
buffer[i % kNumBuffers] = ch;
fullBuffers.signal(); // signal reader there's more stuff to read
cout << oslock << "Writer: published data packet with character '"
<< ch << "'." << endl << osunlock;
}
}
static void reader() {
cout << oslock << "\t\tReader: ready to read." << endl << osunlock;
for (unsigned int i = 0; i < kNumCycles * kNumBuffers; i++) {
fullBuffers.wait(); // don't try to read from a slot unless you know it's full
char ch = buffer[i % kNumBuffers];
emptyBuffers.signal(); // signal writer there's a slot that can receive data
processData(ch);
cout << oslock << "\t\tReader: consumed data packet "
<< "with character '" << ch << "'." << endl << osunlock;
}
}
int main(int argc, const char *argv[]) {
thread w(writer);
thread r(reader);
w.join();
r.join();
return 0;
}
int getNumProcesses(unsigned short num, const unordered_set<string>& sunetIDs);
static unsigned short kMinMythMachine = 1;
static unsigned short kMaxMythMachine = 32;
static void compileCS110ProcessCountMap(const unordered_set<string>& sunetIDs,
map<unsigned short, unsigned short>& counts) {
for (unsigned short num = kMinMythMachine; num <= kMaxMythMachine; num++) {
int numProcesses = getNumProcesses(num, sunetIDs);
if (numProcesses >= 0) { // -1 expresses networking failure
counts[num] = numProcesses;
cout << "myth" << num << " has this many CS110-student processes: "
<< numProcesses << endl;
}
}
}
static unordered_set<string> sunetIDs;
static map<unsigned short, unsigned short> processCountMap;
static mutex processCountMapLock;
static void countCS110Processes(unsigned short num, semaphore& s) {
int numProcesses = getNumProcesses(num, sunetIDs);
if (numProcesses >= 0) {
processCountMapLock.lock();
processCountMap[num] = numProcesses;
processCountMapLock.unlock();
cout << oslock << "myth" << num << " has this many CS110-student processes: "
<< numProcesses << endl << osunlock;
}
s.signal(on_thread_exit);
}
static unsigned short kMinMythMachine = 1;
static unsigned short kMaxMythMachine = 32;
static int kMaxNumThreads = 8; // number of threads beyond main thread that are permitted to exist at any one moment
static void compileCS110ProcessCountMap() {
vector<thread> threads;
semaphore numAllowed(kMaxNumThreads);
for (unsigned short num = kMinMythMachine; num <= kMaxMythMachine; num++) {
numAllowed.wait();
threads.push_back(thread(countCS110Processes, num, ref(numAllowed)));
}
for (thread& t: threads) t.join();
}