Created
December 8, 2021 05:30
-
-
Save ProfAvery/8db86ed1aea0e26cf6c03b924145df65 to your computer and use it in GitHub Desktop.
C++ variants of Figures 29.1, 29.2, and 29.4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <chrono> | |
#include <cstdlib> | |
#include "pthread-wrappers.h" | |
using std::cout; | |
using std::endl; | |
const auto ONE_MILLION = 1'000'000; | |
class Counter | |
{ | |
public: | |
Counter() : value(0){}; | |
int increment(int = 1); | |
int decrement(int = 1); | |
void update(Counter *); | |
int get(); | |
private: | |
int value; | |
Mutex lock; | |
}; | |
int Counter::increment(int amt) | |
{ | |
lock.lock(); | |
value += amt; | |
int rc = value; | |
lock.unlock(); | |
return rc; | |
} | |
int Counter::decrement(int amt) | |
{ | |
lock.lock(); | |
value -= amt; | |
int rc = value; | |
lock.unlock(); | |
return rc; | |
} | |
void Counter::update(Counter *dest) | |
{ | |
lock.lock(); | |
dest->increment(value); | |
value = 0; | |
lock.unlock(); | |
} | |
int Counter::get() | |
{ | |
lock.lock(); | |
auto rc = value; | |
lock.unlock(); | |
return rc; | |
} | |
struct myarg_t | |
{ | |
Counter *global; | |
Counter *local; | |
int threshold; | |
}; | |
void *count(void *arg) | |
{ | |
myarg_t *a = reinterpret_cast<myarg_t *>(arg); | |
for (auto i = 0; i < ONE_MILLION; i++) | |
{ | |
int current = a->local->increment(); | |
if (current >= a->threshold) | |
{ | |
a->local->update(a->global); | |
} | |
} | |
return NULL; | |
} | |
int main(int argc, char *argv[]) | |
{ | |
Counter global, local[4]; | |
Thread t[4]; | |
myarg_t a[4]; | |
int threshold = (argc > 1) ? atoi(argv[1]) : 5; | |
for (auto i = 0; i < 4; i++) | |
{ | |
a[i].global = &global; | |
a[i].local = local + i; | |
a[i].threshold = threshold; | |
} | |
auto start = std::chrono::steady_clock::now(); | |
for (auto i = 0; i < 4; i++) | |
{ | |
t[i].create(count, a + i); | |
} | |
for (auto i = 0; i < 4; i++) | |
{ | |
t[i].join(); | |
} | |
auto end = std::chrono::steady_clock::now(); | |
std::chrono::duration<double> elapsed = end - start; | |
cout << "Counted to " << global.get() << " in " << elapsed.count() | |
<< "s with 4 threads and threshold " << threshold << endl; | |
return EXIT_SUCCESS; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <chrono> | |
#include <cstdlib> | |
#include "pthread-wrappers.h" | |
using std::cout; | |
using std::endl; | |
const auto ONE_MILLION = 1'000'000; | |
class Counter | |
{ | |
public: | |
Counter() : value(0){}; | |
void increment(); | |
void decrement(); | |
int get(); | |
private: | |
int value; | |
Mutex lock; | |
}; | |
void Counter::increment() | |
{ | |
lock.lock(); | |
value++; | |
lock.unlock(); | |
} | |
void Counter::decrement() | |
{ | |
lock.lock(); | |
value--; | |
lock.unlock(); | |
} | |
int Counter::get() | |
{ | |
lock.lock(); | |
auto rc = value; | |
lock.unlock(); | |
return rc; | |
} | |
int main() | |
{ | |
Counter c; | |
auto start = std::chrono::steady_clock::now(); | |
for (auto i = 0; i < 4 * ONE_MILLION; i++) | |
{ | |
c.increment(); | |
} | |
auto end = std::chrono::steady_clock::now(); | |
std::chrono::duration<double> elapsed = end - start; | |
cout << "Counted to " << c.get() << " in " << elapsed.count() | |
<< "s" << endl; | |
return EXIT_SUCCESS; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CXXFLAGS = -g -std=c++17 -Wall -Wextra -Wpedantic -Werror -pthread #-fsanitize=thread | |
SRCS = no-lock-no-threads.cpp \ | |
lock-no-threads.cpp \ | |
single-lock-threaded.cpp \ | |
multiple-lock-threaded.cpp \ | |
approximate.cpp | |
TARGETS = $(SRCS:.cpp=) | |
.PHONY: clean | |
all: $(TARGETS) | |
$(TARGETS): % : %.o pthread-wrappers.o | |
$(CXX) $(CXXFLAGS) -o $@ $^ | |
pthread-wrappers.o: pthread-wrappers.cpp pthread-wrappers.h | |
$(CXX) $(CXXFLAGS) -c $< | |
test: all | |
./no-lock-no-threads | |
./lock-no-threads | |
./single-lock-threaded | |
./multiple-lock-threaded | |
for i in 5 10 20 40 80; do \ | |
./approximate "$$i"; \ | |
done | |
clean: | |
rm -f *.o $(TARGETS) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <chrono> | |
#include <cstdlib> | |
#include "pthread-wrappers.h" | |
using std::cout; | |
using std::endl; | |
const auto ONE_MILLION = 1'000'000; | |
class Counter | |
{ | |
public: | |
Counter() : value(0){}; | |
void increment(); | |
void decrement(); | |
int get(); | |
private: | |
int value; | |
Mutex lock; | |
}; | |
void Counter::increment() | |
{ | |
lock.lock(); | |
value++; | |
lock.unlock(); | |
} | |
void Counter::decrement() | |
{ | |
lock.lock(); | |
value--; | |
lock.unlock(); | |
} | |
int Counter::get() | |
{ | |
lock.lock(); | |
auto rc = value; | |
lock.unlock(); | |
return rc; | |
} | |
void *count(void *arg) | |
{ | |
Counter *c = reinterpret_cast<Counter *>(arg); | |
for (auto i = 0; i < ONE_MILLION; i++) | |
{ | |
c->increment(); | |
} | |
return NULL; | |
} | |
int main() | |
{ | |
Counter c[4]; | |
Thread t[4]; | |
auto start = std::chrono::steady_clock::now(); | |
for (auto i = 0; i < 4; i++) | |
{ | |
void *a = reinterpret_cast<void *>(c + i); | |
t[i].create(count, a); | |
} | |
for (auto i = 0; i < 4; i++) | |
{ | |
t[i].join(); | |
} | |
auto end = std::chrono::steady_clock::now(); | |
std::chrono::duration<double> elapsed = end - start; | |
auto total = 0; | |
for (auto i = 0; i < 4; i++) | |
{ | |
total += c[i].get(); | |
} | |
cout << "Counted to " << total << " in " << elapsed.count() | |
<< "s with 4 threads" << endl; | |
return EXIT_SUCCESS; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <chrono> | |
#include <cstdlib> | |
using std::cout; | |
using std::endl; | |
const auto ONE_MILLION = 1'000'000; | |
class Counter | |
{ | |
public: | |
Counter() : value(0){}; | |
void increment() { value++; }; | |
void decrement() { value--; }; | |
int get() { return value; }; | |
private: | |
int value; | |
}; | |
int main() | |
{ | |
Counter c; | |
auto start = std::chrono::steady_clock::now(); | |
for (auto i = 0; i < 4 * ONE_MILLION; i++) | |
{ | |
c.increment(); | |
} | |
auto end = std::chrono::steady_clock::now(); | |
std::chrono::duration<double> elapsed = end - start; | |
cout << "Counted to " << c.get() << " in " << elapsed.count() | |
<< "s" << endl; | |
return EXIT_SUCCESS; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cstdio> | |
#include <cstdlib> | |
#include <cerrno> | |
#include "pthread-wrappers.h" | |
void Thread::create(void *(*routine)(void *), void *arg) | |
{ | |
errno = pthread_create(&tid, NULL, routine, arg); | |
if (errno != 0) { | |
perror("pthread_create"); | |
exit(EXIT_FAILURE); | |
} | |
} | |
void *Thread::join() | |
{ | |
void *retval; | |
errno = pthread_join(tid, &retval); | |
if (errno != 0) { | |
perror("pthread_join"); | |
exit(EXIT_FAILURE); | |
} | |
return retval; | |
} | |
Mutex::Mutex() | |
{ | |
errno = pthread_mutex_init(&mutex, NULL); | |
if (errno != 0) { | |
perror("pthread_mutex_init"); | |
exit(EXIT_FAILURE); | |
} | |
} | |
Mutex::~Mutex() | |
{ | |
errno = pthread_mutex_destroy(&mutex); | |
if (errno != 0) { | |
perror("pthread_mutex_destroy"); | |
exit(EXIT_FAILURE); | |
} | |
} | |
void Mutex::lock() | |
{ | |
errno = pthread_mutex_lock(&mutex); | |
if (errno != 0) { | |
perror("pthread_mutex_lock"); | |
exit(EXIT_FAILURE); | |
} | |
} | |
void Mutex::unlock() | |
{ | |
errno = pthread_mutex_unlock(&mutex); | |
if (errno != 0) { | |
perror("pthread_mutex_unlock"); | |
exit(EXIT_FAILURE); | |
} | |
} | |
Cond::Cond() | |
{ | |
errno = pthread_cond_init(&cond, NULL); | |
if (errno != 0) { | |
perror("pthread_cond_init"); | |
exit(EXIT_FAILURE); | |
} | |
} | |
Cond::~Cond() | |
{ | |
errno = pthread_cond_destroy(&cond); | |
if (errno != 0) { | |
perror("pthread_cond_destroy"); | |
exit(EXIT_FAILURE); | |
} | |
} | |
void Cond::wait(Mutex &m) | |
{ | |
errno = pthread_cond_wait(&cond, &m.mutex); | |
if (errno != 0) { | |
perror("pthread_cond_wait"); | |
exit(EXIT_FAILURE); | |
} | |
} | |
void Cond::signal() | |
{ | |
errno = pthread_cond_signal(&cond); | |
if (errno != 0) { | |
perror("pthread_cond_signal"); | |
exit(EXIT_FAILURE); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef PTHREAD_WRAPPERS_H | |
#define PTHREAD_WRAPPERS_H | |
#include <pthread.h> | |
class Thread { | |
public: | |
void create(void *(*thread)(void *), void * = NULL); | |
void *join(); | |
private: | |
pthread_t tid; | |
}; | |
class Mutex { | |
friend class Cond; | |
public: | |
Mutex(); | |
~Mutex(); | |
void lock(); | |
void unlock(); | |
private: | |
pthread_mutex_t mutex; | |
}; | |
class Cond { | |
public: | |
Cond(); | |
~Cond(); | |
void wait(Mutex &); | |
void signal(); | |
private: | |
pthread_cond_t cond; | |
}; | |
#endif |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <chrono> | |
#include <cstdlib> | |
#include "pthread-wrappers.h" | |
using std::cout; | |
using std::endl; | |
const auto ONE_MILLION = 1'000'000; | |
class Counter | |
{ | |
public: | |
Counter() : value(0){}; | |
void increment(); | |
void decrement(); | |
int get(); | |
private: | |
int value; | |
Mutex lock; | |
}; | |
void Counter::increment() | |
{ | |
lock.lock(); | |
value++; | |
lock.unlock(); | |
} | |
void Counter::decrement() | |
{ | |
lock.lock(); | |
value--; | |
lock.unlock(); | |
} | |
int Counter::get() | |
{ | |
lock.lock(); | |
int rc = value; | |
lock.unlock(); | |
return rc; | |
} | |
void *count(void *arg) | |
{ | |
Counter *c = reinterpret_cast<Counter *>(arg); | |
for (auto i = 0; i < ONE_MILLION; i++) | |
{ | |
c->increment(); | |
} | |
return NULL; | |
} | |
int main() | |
{ | |
Counter c; | |
Thread t[4]; | |
void *a = reinterpret_cast<void *>(&c); | |
auto start = std::chrono::steady_clock::now(); | |
for (auto i = 0; i < 4; i++) | |
{ | |
t[i].create(count, a); | |
} | |
for (auto i = 0; i < 4; i++) | |
{ | |
t[i].join(); | |
} | |
auto end = std::chrono::steady_clock::now(); | |
std::chrono::duration<double> elapsed = end - start; | |
cout << "Counted to " << c.get() << " in " << elapsed.count() | |
<< "s with 4 threads" << endl; | |
return EXIT_SUCCESS; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment