Principles of Computer Systems
Fall 2019
Stanford University
Computer Science Department
Instructors: Chris Gregg and
Philip Levis
static void philosopher(size_t id, mutex& left, mutex& right) {
for (size_t i = 0; i < 3; i++) {
think(id);
eat(id, left, right);
}
}
int main(int argc, const char *argv[]) {
mutex forks[5];
thread philosophers[5];
for (size_t i = 0; i < 5; i++) {
mutex& left = forks[i], & right = forks[(i + 1) % 5];
philosophers[i] = thread(philosopher, i, ref(left), ref(right));
}
for (thread& p: philosophers) p.join();
return 0;
}
static void think(size_t id) {
cout << oslock << id << " starts thinking." << endl << osunlock;
sleep_for(getThinkTime());
cout << oslock << id << " all done thinking. " << endl << osunlock;
}
static void eat(size_t id, mutex& left, mutex& right) {
left.lock();
right.lock();
cout << oslock << id << " starts eating om nom nom nom." << endl << osunlock;
sleep_for(getEatTime());
cout << oslock << id << " all done eating." << endl << osunlock;
left.unlock();
right.unlock();
}
static void eat(size_t id, mutex& left, mutex& right) {
left.lock();
sleep_for(5000); // artificially force off the processor
right.lock();
cout << oslock << id << " starts eating om nom nom nom." << endl << osunlock;
sleep_for(getEatTime());
cout << oslock << id << " all done eating." << endl << osunlock;
left.unlock();
right.unlock();
}
int main(int argc, const char *argv[]) {
size_t permits = 4;
mutex forks[5], permitsLock;
thread philosophers[5];
for (size_t i = 0; i < 5; i++) {
mutex& left = forks[i],
& right = forks[(i + 1) % 5];
philosophers[i] =
thread(philosopher, i, ref(left), ref(right), ref(permits), ref(permitsLock));
}
for (thread& p: philosophers) p.join();
return 0;
}
static void eat(size_t id, mutex& left, mutex& right, size_t& permits, mutex& permitsLock) {
waitForPermission(permits, permitsLock); // on next slide
left.lock(); right.lock();
cout << oslock << id << " starts eating om nom nom nom." << endl << osunlock;
sleep_for(getEatTime());
cout << oslock << id << " all done eating." << endl << osunlock;
grantPermission(permits, permitsLock); // on next slide
left.unlock(); right.unlock();
}
static void philosopher(size_t id, mutex& left, mutex& right,
size_t& permits, mutex& permitsLock) {
for (size_t i = 0; i < kNumMeals; i++) {
think(id);
eat(id, left, right, permits, permitsLock);
}
}
static void waitForPermission(size_t& permits, mutex& permitsLock) {
while (true) {
permitsLock.lock();
if (permits > 0) break;
permitsLock.unlock();
sleep_for(10);
}
permits--;
permitsLock.unlock();
}
static void grantPermission(size_t& permits, mutex& permitsLock) {
permitsLock.lock();
permits++;
permitsLock.unlock();
}
class condition_variable_any {
public:
void wait(mutex& m);
template <typename Pred> void wait(mutex& m, Pred pred);
void notify_one();
void notify_all();
};
int main(int argc, const char *argv[]) {
size_t permits = 4;
mutex forks[5], m;
condition_variable_any cv;
thread philosophers[5];
for (size_t i = 0; i < 5; i++) {
mutex& left = forks[i], & right = forks[(i + 1) % 5];
philosophers[i] =
thread(philosopher, i, ref(left), ref(right), ref(permits), ref(cv), ref(m));
}
for (thread& p: philosophers) p.join();
return 0;
}
static void waitForPermission(size_t& permits, condition_variable_any& cv, mutex& m) {
lock_guard<mutex> lg(m);
while (permits == 0) cv.wait(m);
permits--;
}
static void grantPermission(size_t& permits, condition_variable_any& cv, mutex& m) {
lock_guard<mutex> lg(m);
permits++;
if (permits == 1) cv.notify_all();
}
static void waitForPermission(size_t& permits, condition_variable_any& cv, mutex& m) {
lock_guard<mutex> lg(m);
while (permits == 0) cv.wait(m);
permits--;
}
static void grantPermission(size_t& permits, condition_variable_any& cv, mutex& m) {
lock_guard<mutex> lg(m);
permits++;
if (permits == 1) cv.notify_all();
}
template <Predicate pred>
void condition_variable_any::wait(mutex& m, Pred pred) {
while (!pred()) wait(m);
}
static void waitForPermission(size_t& permits, condition_variable_any& cv, mutex& m) {
lock_guard<mutex> lg(m);
cv.wait(m, [&permits] { return permits > 0; });
permits--;
}
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 void philosopher(size_t id, mutex& left, mutex& right, semaphore& permits) {
for (size_t i = 0; i < 3; i++) {
think(id);
eat(id, left, right, permits);
}
}
int main(int argc, const char *argv[]) {
semaphore permits(4);
mutex forks[5];
thread philosophers[5];
for (size_t i = 0; i < 5; i++) {
mutex& left = forks[i], & right = forks[(i + 1) % 5];
philosophers[i] = thread(philosopher, i, ref(left), ref(right), ref(permits));
}
for (thread& p: philosophers) p.join();
return 0;
}
static void eat(size_t id, mutex& left, mutex& right, semaphore& permits) {
permits.wait();
left.lock();
right.lock();
cout << oslock << id << " starts eating om nom nom nom." << endl << osunlock;
sleep_for(getEatTime());
cout << oslock << id << " all done eating." << endl << osunlock;
permits.signal();
left.unlock();
right.unlock();
}
static void writer(char buffer[]) {
cout << oslock << "Writer: ready to write." << endl << osunlock;
for (size_t i = 0; i < 320; i++) { // 320 is 40 cycles around the circular buffer of length 8
char ch = prepareData();
buffer[i % 8] = ch;
cout << oslock << "Writer: published data packet with character '"
<< ch << "'." << endl << osunlock;
}
}
static void reader(char buffer[]) {
cout << oslock << "\t\tReader: ready to read." << endl << osunlock;
for (size_t i = 0; i < 320; i++) { // 320 is 40 cycles around the circular buffer of length 8
char ch = buffer[i % 8];
processData(ch);
cout << oslock << "\t\tReader: consumed data packet " << "with character '"
<< ch << "'." << endl << osunlock;
}
}
int main(int argc, const char *argv[]) {
char buffer[8];
thread w(writer, buffer);
thread r(reader, buffer);
w.join();
r.join();
return 0;
}
int main(int argc, const char *argv[]) {
char buffer[8];
semaphore fullBuffers, emptyBuffers(8);
thread w(writer, buffer, ref(fullBuffers), ref(emptyBuffers));
thread r(reader, buffer, ref(fullBuffers), ref(emptyBuffers));
w.join();
r.join();
return 0;
}
static void writer(char buffer[], semaphore& full, semaphore& empty) {
cout << oslock << "Writer: ready to write." << endl << osunlock;
for (size_t i = 0; i < 320; i++) { // 320 is 40 cycles around the circular buffer of length 8
char ch = prepareData();
empty.wait(); // don't try to write to a slot unless you know it's empty
buffer[i % 8] = ch;
full.signal(); // signal reader there's more stuff to read
cout << oslock << "Writer: published data packet with character '"
<< ch << "'." << endl << osunlock;
}
}
static void reader(char buffer[], semaphore& full, semaphore& empty) {
cout << oslock << "\t\tReader: ready to read." << endl << osunlock;
for (size_t i = 0; i < 320; i++) { // 320 is 40 cycles around the circular buffer of length 8
full.wait(); // don't try to read from a slot unless you know it's full
char ch = buffer[i % 8];
empty.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;
}
}