Skip to content

Instantly share code, notes, and snippets.

@ProfAvery
Last active October 8, 2020 09:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ProfAvery/e31f0630cb5ea904e60dddbf82a4d50d to your computer and use it in GitHub Desktop.
Save ProfAvery/e31f0630cb5ea904e60dddbf82a4d50d to your computer and use it in GitHub Desktop.
POSIX Multithreading Example
burncpu
multithread
mutex
semaphore
#include <cstdlib>
int main()
{
while (true) {
// waste time
}
return EXIT_SUCCESS;
}
CXXFLAGS = -g -std=c++17 -Wall -Wextra -Wpedantic -pthread
TARGETS = burncpu multithread mutex semaphore
.PHONY: test check check-leaks check-threads clean
all: $(TARGETS)
test: $(TARGETS)
sh ./test.sh
check: check-leaks check-threads
check-leaks: multithread mutex semaphore
for exe in $^; do valgrind --quiet ./$$exe 5 ; done
check-threads: multithread mutex semaphore
for exe in $^; do valgrind --tool=helgrind --quiet ./$$exe 5 ; done
clean:
rm -f $(TARGETS)
#include <cstdlib>
#include <iostream>
#include <vector>
#include <pthread.h>
using std::cout;
using std::cerr;
using std::endl;
using std::vector;
int sum = 0;
void *runner(void *);
int main(int argc, char *argv[])
{
if (argc != 2) {
cerr << "Usage: " << argv[0] << " N" << endl;
return EXIT_FAILURE;
}
auto n = atoi(argv[1]);
vector<pthread_t> tids;
for (auto i = 0; i < n; i++) {
auto pi = new int[1];
*pi = i;
pthread_t tid;
errno = pthread_create(&tid, NULL, runner, pi);
if (errno != 0) {
perror("pthread_create");
return EXIT_FAILURE;
}
tids.push_back(tid);
}
for (auto tid : tids) {
errno = pthread_join(tid, NULL);
if (errno != 0) {
perror("pthread_join");
return EXIT_FAILURE;
}
}
cout << "sum = " << sum << endl;
return EXIT_SUCCESS;
}
void *runner(void *param)
{
int *pi = reinterpret_cast<int *>(param);
sum += *pi;
delete[] pi;
pthread_exit(NULL);
}
#include <cstdlib>
#include <iostream>
#include <vector>
#include <pthread.h>
using std::cout;
using std::cerr;
using std::endl;
using std::vector;
int sum = 0;
pthread_mutex_t mutex;
void *runner(void *);
int main(int argc, char *argv[])
{
if (argc != 2) {
cerr << "Usage: " << argv[0] << " N" << endl;
return EXIT_FAILURE;
}
auto n = atoi(argv[1]);
errno = pthread_mutex_init(&mutex, NULL);
if (errno != 0) {
perror("pthread_mutex_init");
return EXIT_FAILURE;
}
vector<pthread_t> tids;
for (auto i = 0; i < n; i++) {
auto pi = new int[1];
*pi = i;
pthread_t tid;
errno = pthread_create(&tid, NULL, runner, pi);
if (errno != 0) {
perror("pthread_create");
return EXIT_FAILURE;
}
tids.push_back(tid);
}
for (auto tid : tids) {
errno = pthread_join(tid, NULL);
if (errno != 0) {
perror("pthread_join");
return EXIT_FAILURE;
}
}
cout << "sum = " << sum << endl;
errno = pthread_mutex_destroy(&mutex);
if (errno != 0) {
perror("pthread_mutex_destroy");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
void *runner(void *param)
{
int *pi = reinterpret_cast<int *>(param);
// errno is thread-local, so safe to change in a thread
errno = pthread_mutex_lock(&mutex);
if (errno != 0) {
perror("pthread_mutex_lock");
// not in main(), so need to explicitly exit() instead of return
exit(EXIT_FAILURE);
}
sum += *pi;
errno = pthread_mutex_unlock(&mutex);
if (errno != 0) {
perror("pthread_mutex_unlock");
exit(EXIT_FAILURE);
}
delete[] pi;
pthread_exit(NULL);
}
#include <cstdlib>
#include <iostream>
#include <vector>
#include <pthread.h>
#include <semaphore.h>
using std::cout;
using std::cerr;
using std::endl;
using std::vector;
int sum = 0;
sem_t sem;
void *runner(void *);
int main(int argc, char *argv[])
{
if (argc != 2) {
cerr << "Usage: " << argv[0] << " N" << endl;
return EXIT_FAILURE;
}
auto n = atoi(argv[1]);
auto ok = sem_init(&sem, 0, 1);
if (ok < 0) {
perror("sem_init");
return EXIT_FAILURE;
}
vector<pthread_t> tids;
for (auto i = 0; i < n; i++) {
auto pi = new int[1];
*pi = i;
pthread_t tid;
errno = pthread_create(&tid, NULL, runner, pi);
if (errno != 0) {
perror("pthread_create");
return EXIT_FAILURE;
}
tids.push_back(tid);
}
for (auto tid : tids) {
errno = pthread_join(tid, NULL);
if (errno != 0) {
perror("pthread_join");
return EXIT_FAILURE;
}
}
cout << "sum = " << sum << endl;
ok = sem_destroy(&sem);
if (ok < 0) {
perror("sem_destroy");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
void *runner(void *param)
{
int *pi = reinterpret_cast<int *>(param);
auto ok = sem_wait(&sem);
if (ok < 0) {
perror("sem_wait");
// not in main(), so need to explicitly exit() instead of return
exit(EXIT_FAILURE);
}
sum += *pi;
ok = sem_post(&sem);
if (ok < 0) {
perror("sem_post");
exit(EXIT_FAILURE);
}
delete[] pi;
pthread_exit(NULL);
}
#!/bin/sh
./burncpu &
echo Without mutexes or semaphores
for i in $(seq 1 100); do
./multithread 1000
done | sort -u
echo With mutex
for i in $(seq 1 100); do
./mutex 1000
done | sort -u
echo With semaphore
for i in $(seq 1 100); do
./semaphore 1000
done | sort -u
pkill burncpu
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment