Autumn 2021
Jerry Cain
PDF
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;
}
poohbear@myth61:$ ./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)
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
};
When there are multiple threads writing to a variable.
When there is a thread writing and one or more threads reading
Why do you not need a mutex when there are no writers (only readers)?
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;
}
critical region