Last active
October 8, 2020 09:04
-
-
Save ProfAvery/e31f0630cb5ea904e60dddbf82a4d50d to your computer and use it in GitHub Desktop.
POSIX Multithreading Example
This file contains 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
burncpu | |
multithread | |
mutex | |
semaphore |
This file contains 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 <cstdlib> | |
int main() | |
{ | |
while (true) { | |
// waste time | |
} | |
return EXIT_SUCCESS; | |
} |
This file contains 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 -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) |
This file contains 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 <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); | |
} |
This file contains 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 <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); | |
} |
This file contains 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 <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); | |
} |
This file contains 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
#!/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