Skip to content

Instantly share code, notes, and snippets.

@ProfAvery
Created December 8, 2021 05:30
Show Gist options
  • Save ProfAvery/8db86ed1aea0e26cf6c03b924145df65 to your computer and use it in GitHub Desktop.
Save ProfAvery/8db86ed1aea0e26cf6c03b924145df65 to your computer and use it in GitHub Desktop.
C++ variants of Figures 29.1, 29.2, and 29.4
#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;
}
#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;
}
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)
#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;
}
#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;
}
#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);
}
}
#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
#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