Principles of Computer Systems
Spring 2019
Stanford University
Computer Science Department
Lecturer: Chris Gregg
fork
/ execvp
child processes and manage them through the use of signal handlers. It also tests your ability to use pipes.assign3/samples/stsh_soln
)ls | grep stsh | cut -d- -f2
stsh.cc
static void recharge() {
cout << oslock << "I recharge by spending time alone." << endl << osunlock;
}
static const size_t kNumIntroverts = 6;
int main(int argc, char *argv[]) {
cout << "Let's hear from " << kNumIntroverts << " introverts." << endl
thread introverts[kNumIntroverts]; // declare array of empty thread handles
for (thread& introvert: introverts)
introvert = thread(recharge); // move anonymous threads into empty handles
for (thread& introvert: introverts)
introvert.join();
cout << "Everyone's recharged!" << endl;
return 0;
}
static void greet(size_t id) {
for (size_t i = 0; i < id; i++) {
cout << oslock << "Greeter #" << id << " says 'Hello!'" << endl << osunlock;
struct timespec ts = {
0, random() % 1000000000
};
nanosleep(&ts, NULL);
}
cout << oslock << "Greeter #" << id << " has issued all of his hellos, "
<< "so he goes home!" << endl << osunlock;
}
static const size_t kNumGreeters = 6;
int main(int argc, char *argv[]) {
cout << "Welcome to Greetland!" << endl;
thread greeters[kNumGreeters];
for (size_t i = 0; i < kNumGreeters; i++) greeters[i] = thread(greet, i + 1);
for (thread& greeter: greeters) greeter.join();
cout << "Everyone's all greeted out!" << endl;
return 0;
}
int main(int argc, const char *argv[]) {
thread agents[10];
size_t remainingTickets = 250;
for (size_t i = 0; i < 10; i++)
agents[i] = thread(ticketAgent, 101 + i, ref(remainingTickets));
for (thread& agent: agents) agent.join();
cout << "End of Business Day!" << endl;
return 0;
}
int main(int argc, const char *argv[]) {
thread agents[10];
size_t remainingTickets = 250;
for (size_t i = 0; i < 10; i++)
agents[i] = thread(ticketAgent, 101 + i, ref(remainingTickets));
for (thread& agent: agents) agent.join();
cout << "End of Business Day!" << endl;
return 0;
}
static void ticketAgent(size_t id, size_t& remainingTickets) {
while (remainingTickets > 0) {
handleCall(); // sleep for a small amount of time to emulate conversation time.
remainingTickets--;
cout << oslock << "Agent #" << id << " sold a ticket! (" << remainingTickets
<< " more to be sold)." << endl << osunlock;
if (shouldTakeBreak()) // flip a biased coin
takeBreak(); // if comes up heads, sleep for a random time to take a break
}
cout << oslock << "Agent #" << id << " notices all tickets are sold, and goes home!"
<< endl << osunlock;
}
cgregg@myth55$ ./confused-ticket-agents
Agent #110 sold a ticket! (249 more to be sold).
Agent #104 sold a ticket! (248 more to be sold).
Agent #106 sold a ticket! (247 more to be sold).
// some 245 lines omitted for brevity
Agent #107 sold a ticket! (1 more to be sold).
Agent #103 sold a ticket! (0 more to be sold).
Agent #105 notices all tickets are sold, and goes home!
Agent #104 notices all tickets are sold, and goes home!
Agent #108 sold a ticket! (4294967295 more to be sold).
Agent #106 sold a ticket! (4294967294 more to be sold).
Agent #102 sold a ticket! (4294967293 more to be sold).
Agent #101 sold a ticket! (4294967292 more to be sold).
// carries on for a very, very, very long time
0x0000000000401a9b <+36>: mov -0x20(%rbp),%rax
0x0000000000401a9f <+40>: mov (%rax),%eax
0x0000000000401aa1 <+42>: lea -0x1(%rax),%edx
0x0000000000401aa4 <+45>: mov -0x20(%rbp),%rax
0x0000000000401aa8 <+49>: mov %edx,(%rax)
0x0000000000401a9b <+36>: mov -0x20(%rbp),%rax
0x0000000000401a9f <+40>: mov (%rax),%eax
0x0000000000401aa1 <+42>: lea -0x1(%rax),%edx
0x0000000000401aa4 <+45>: mov -0x20(%rbp),%rax
0x0000000000401aa8 <+49>: mov %edx,(%rax)
class mutex {
public:
mutex(); // constructs the mutex to be in an unlocked state
void lock(); // acquires the lock on the mutex, blocking until it's unlocked
void unlock(); // releases the lock and wakes up another threads trying to lock it
};
class mutex {
public:
mutex(); // constructs the mutex to be in an unlocked state
void lock(); // acquires the lock on the mutex, blocking until it's unlocked
void unlock(); // releases the lock and wakes up another threads trying to lock it
};
static void ticketAgent(size_t id, size_t& remainingTickets, mutex& ticketsLock) {
while (true) {
ticketsLock.lock();
if (remainingTickets == 0) break;
handleCall();
remainingTickets--;
cout << oslock << "Agent #" << id << " sold a ticket! (" << remainingTickets
<< " more to be sold)." << endl << osunlock;
ticketsLock.unlock();
if (shouldTakeBreak()) takeBreak();
}
ticketsLock.unlock();
cout << oslock << "Agent #" << id << " notices all tickets are sold, and goes home!"
<< endl << osunlock;
}
int main(int argc, const char *argv[]) {
size_t remainingTickets = 250;
mutex ticketsLock;
thread agents[10];
for (size_t i = 0; i < 10; i++)
agents[i] = thread(ticketAgent, 101 + i, ref(remainingTickets), ref(ticketsLock));
for (thread& agent: agents) agent.join();
cout << "End of Business Day!" << endl;
return 0;
}
static void ticketAgent(size_t id, size_t& remainingTickets, mutex& ticketsLock) {
while (true) {
ticketsLock.lock();
if (remainingTickets == 0) break;
handleCall();
remainingTickets--;
cout << oslock << "Agent #" << id << " sold a ticket! (" << remainingTickets
<< " more to be sold)." << endl << osunlock;
ticketsLock.unlock();
if (shouldTakeBreak()) takeBreak();
}
ticketsLock.unlock();
cout << oslock << "Agent #" << id << " notices all tickets are sold, and goes home!"
<< endl << osunlock;
}
static void ticketAgent(size_t id, size_t& remainingTickets, mutex& ticketsLock) {
while (true) {
ticketsLock.lock();
if (remainingTickets == 0) break;
remainingTickets--;
ticketsLock.unlock();
handleCall(); // assume this sale is successful
cout << oslock << "Agent #" << id << " sold a ticket! (" << remainingTickets
<< " more to be sold)." << endl << osunlock;
if (shouldTakeBreak()) takeBreak();
}
ticketsLock.unlock();
cout << oslock << "Agent #" << id << " notices all tickets are sold, and goes home!"
<< endl << osunlock;
}