By introducing threading, we overlay the network stall times.
- Multithreaded version of the program is right here.
- Move shared data structures and synchronization directives to global space
static unordered_set<string> sunetIDs;
static map<unsigned short, unsigned short> processCountMap;
static mutex processCountMapLock;
- Wrap a thread around the core of the sequential code, and use a semaphore to limit the number of threads doing active work to a reasonably small number (but not so small that the program becomes sequential again) so that the thread manager doesn't get overloaded with all that many threads.
- Note we use an overloaded version of the signal method that accepts the on_thread_exit tag as its only argument. Rather than signaling the semaphore right then and there, invoking this second version schedules the signal to be sent after the entire thread routine has exited, just as the thread is being destroyed.
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();
}