Skip to content

Commit 4f8d6e3

Browse files
committed
cpp: add some more threading
1 parent b80ccb4 commit 4f8d6e3

10 files changed

Lines changed: 179 additions & 117 deletions

File tree

‎cpp/README.md‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,14 @@
8787
1. [sstream](sstream.cpp)
8888
1. [iostream](iostream.cpp)
8989
1. [File IO](file_io.cpp)
90-
1. [thread](thread.cpp)
91-
1. [sleep_for](sleep_for.cpp)
90+
1. Multi-threading
91+
1. [thread::hardware_concurrency](thread_hardware_concurrency.cpp)
92+
1. [thread::this_thread::sleep_for](sleep_for.cpp)
93+
1. [thread return value](thread_return_value.cpp)
9294
1. [atomic](atomic.cpp)
9395
1. [atomic<bool>](atomic_bool.cpp.off)
94-
1. [mutex](mutex.cpp)
96+
1. [sleep_for](interactive/sleep_for.cpp)
97+
1. [mutex](interactive/mutex.cpp)
9598
1. [algorithm](algorithm.cpp)
9699
1. [heap](heap.cpp)
97100
1. [functional](functional.cpp)
@@ -115,9 +118,6 @@
115118
1. [bst_vs_heap](interactive/bst_vs_heap.cpp)
116119
1. [chrono](interactive/chrono.cpp)
117120
1. [random](interactive/random.cpp)
118-
1. thread
119-
1. [sleep_for](interactive/sleep_for.cpp)
120-
1. [thread_count](interactive/thread_count.cpp)
121121
1. Applications
122122
1. [Design patterns](design_patterns.cpp)
123123

‎cpp/interactive/mutex.cpp‎

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// Only allows one thread to enter the critical zone.
2+
//
3+
// Usage:
4+
//
5+
// ./mutex.out [num_iters [num_threads [use_mutex=0|1]]
6+
//
7+
// Should work because uses mutex:
8+
//
9+
// ./mutex.out 1000 10 1
10+
//
11+
// Fails for large num_iters large enough with more than one thread
12+
// due to synchroniation problems:
13+
//
14+
// ./mutex.out 1000 10 0
15+
//
16+
// This is an artificial example: the more restricted and efficient atomic would be a better fit.
17+
//
18+
// http://stackoverflow.com/questions/6837699/are-mutex-lock-functions-sufficient-without-volatile
19+
20+
#if __cplusplus >= 201103L
21+
#include <cassert>
22+
#include <iostream>
23+
#include <mutex>
24+
#include <thread>
25+
#include <vector>
26+
27+
std::mutex mutex;
28+
unsigned int num_threads;
29+
unsigned int use_mutex = 1;
30+
unsigned long global = 0;
31+
unsigned long long num_iters = 0;
32+
33+
void thread_main() {
34+
for (decltype(num_iters) i = 0; i < num_iters; ++i) {
35+
if (use_mutex)
36+
mutex.lock();
37+
global++;
38+
if (use_mutex)
39+
mutex.unlock();
40+
}
41+
}
42+
#endif
43+
44+
int main(int argc, char **argv) {
45+
#if __cplusplus >= 201103L
46+
if (argc > 1) {
47+
num_iters = std::strtoull(argv[1], NULL, 10);
48+
} else {
49+
num_iters = 10;
50+
}
51+
if (argc > 2) {
52+
num_threads = std::strtoull(argv[2], NULL, 10);
53+
} else {
54+
num_threads = std::thread::hardware_concurrency();
55+
}
56+
if (argc > 3) {
57+
use_mutex = (argv[3][0] == '1');
58+
} else {
59+
use_mutex = 1;
60+
}
61+
62+
std::vector<std::thread> threads(num_threads);
63+
for (auto& thread : threads)
64+
thread = std::thread(thread_main);
65+
for (auto& thread : threads)
66+
thread.join();
67+
auto num_ops = num_threads * num_iters;
68+
if (global != num_ops) {
69+
std::cout << "fraction of errors " << ((double)global / num_ops) << std::endl;
70+
assert(false);
71+
}
72+
#endif
73+
}

‎cpp/interactive/sleep_for.cpp‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// Count to infinity sleeping one second per number.
2+
13
#include "common.hpp"
24

35
int main() {

‎cpp/interactive/thread_count.cpp‎

Lines changed: 0 additions & 20 deletions
This file was deleted.

‎cpp/mutex.cpp‎

Lines changed: 0 additions & 44 deletions
This file was deleted.

‎cpp/thread.cpp‎

Lines changed: 0 additions & 33 deletions
This file was deleted.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// http://stackoverflow.com/questions/150355/programmatically-find-the-number-of-cores-on-a-machine
2+
//
3+
// Not affected by taskset: https://stackoverflow.com/questions/1006289/how-to-find-out-the-number-of-cpus-using-python/55423170#55423170
4+
5+
#include <iostream>
6+
#include <thread>
7+
8+
int main() {
9+
std::cout << std::thread::hardware_concurrency() << std::endl;
10+
}

‎cpp/thread_id.cpp‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Spawn some threads and print their ID.
2+
//
3+
// On Ubuntu 19.04, they were not consecutive numbers.
4+
5+
#include <iostream>
6+
#include <mutex>
7+
#include <thread>
8+
#include <vector>
9+
10+
std::mutex mutex;
11+
12+
void myfunc(int i) {
13+
mutex.lock();
14+
std::cout << i << " " << std::this_thread::get_id() << std::endl;
15+
mutex.unlock();
16+
}
17+
18+
int main() {
19+
std::cout << "main " << std::this_thread::get_id() << std::endl;
20+
std::vector<std::thread> threads;
21+
for (unsigned int i = 0; i < 4; ++i) {
22+
threads.push_back(std::thread(myfunc, i));
23+
}
24+
for (auto& thread : threads) {
25+
thread.join();
26+
}
27+
}

‎cpp/thread_return_value.cpp‎

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,64 @@
1-
/*
2-
# thread return value
1+
// http://stackoverflow.com/questions/7686939/c-simple-return-value-from-stdthread
2+
// http://stackoverflow.com/questions/28950835/c-error-no-type-named-type-in-class-stdresult-ofvoid-stdunordered
3+
// http://stackoverflow.com/questions/21048906/stdthread-pass-by-reference-calls-copy-constructor
4+
// http://stackoverflow.com/questions/8299545/passing-arguments-to-thread-function
5+
// http://stackoverflow.com/questions/5116756/difference-between-pointer-and-reference-as-thread-parameter
36

4-
An actual return value is impossible, you need to use other wrappers:
7+
#include <cassert>
8+
#include <future>
9+
#include <iostream>
10+
#include <mutex>
11+
#include <thread>
12+
#include <vector>
513

6-
- http://stackoverflow.com/questions/7686939/c-simple-return-value-from-stdthread
14+
std::mutex mutex;
715

8-
Shared state will of course work.
16+
int myfunc(int i) {
17+
return i + 1;
18+
}
919

10-
Passing reference arguments to be modified has weird results:
20+
void myfunc_reference(int& i) {
21+
i = myfunc(i);
22+
}
1123

12-
- http://stackoverflow.com/questions/28950835/c-error-no-type-named-type-in-class-stdresult-ofvoid-stdunordered
13-
- http://stackoverflow.com/questions/21048906/stdthread-pass-by-reference-calls-copy-constructor
14-
- http://stackoverflow.com/questions/8299545/passing-arguments-to-thread-function
15-
- http://stackoverflow.com/questions/5116756/difference-between-pointer-and-reference-as-thread-parameter
16-
*/
24+
int main() {
25+
unsigned int nthreads = 4;
26+
std::vector<int> inputs{1, 2, 3, 4};
27+
std::vector<int> outputs_expect{2, 3, 4, 5};
1728

18-
#include "common.hpp"
29+
// future and sync. Nirvana. When you are not fighting to death with types:
30+
// https://stackoverflow.com/questions/10620300/can-stdasync-be-use-with-template-functions
31+
{
32+
std::vector<std::future<int>> futures(nthreads);
33+
std::vector<int> outputs(nthreads);
34+
for (decltype(futures)::size_type i = 0; i < nthreads; ++i) {
35+
futures[i] = std::async(
36+
myfunc,
37+
inputs[i]
38+
);
39+
}
40+
for (decltype(futures)::size_type i = 0; i < nthreads; ++i) {
41+
outputs[i] = futures[i].get();
42+
}
43+
assert(outputs_expect == outputs);
44+
}
1945

20-
int main() {
21-
// TODO
46+
// Reference arguments.
47+
//
48+
// Annoying because requires:
49+
//
50+
// - wrapping the return function to accept references
51+
// - keeping an array of outputs
52+
// - std::ref
53+
{
54+
std::vector<std::thread> threads(nthreads);
55+
std::vector<int> inouts(inputs);
56+
for (decltype(threads)::size_type i = 0; i < nthreads; ++i) {
57+
threads[i] = std::thread(myfunc_reference, std::ref(inouts[i]));
58+
}
59+
for (auto& thread : threads) {
60+
thread.join();
61+
}
62+
assert(outputs_expect == inouts);
63+
}
2264
}

‎shared_library/basic/README.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
11
# Basic
22

33
Basic example. Creates a shared and a static library from `a.c` and `b.c`.
4+
5+
Used in the following answers:
6+
7+
- https://unix.stackexchange.com/questions/89211/how-to-test-whether-a-linux-binary-was-compiled-as-position-independent-code/435038#435038
8+
- https://unix.stackexchange.com/questions/226524/what-system-call-is-used-to-load-libraries-in-linux/462710#462710

0 commit comments

Comments
 (0)