mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-23 02:05:57 +01:00
userland: move more multithreading from cpp-cheat!
Convert infinite_loop.c into loop.c. Keep all examples fast by default!
This commit is contained in:
17
README.adoc
17
README.adoc
@@ -12845,7 +12845,7 @@ Programs under link:userland/c/[] are examples of https://en.wikipedia.org/wiki/
|
|||||||
*** File IO
|
*** File IO
|
||||||
**** link:userland/c/file_write_read.c[]
|
**** link:userland/c/file_write_read.c[]
|
||||||
* Fun
|
* Fun
|
||||||
** link:userland/c/infinite_loop.c[]
|
** link:userland/c/loop.c[]
|
||||||
|
|
||||||
==== malloc
|
==== malloc
|
||||||
|
|
||||||
@@ -12949,6 +12949,16 @@ It then walks over every page and writes a value in it to ensure that it is used
|
|||||||
|
|
||||||
Algorithm used by the OOM: https://unix.stackexchange.com/questions/153585/how-does-the-oom-killer-decide-which-process-to-kill-first
|
Algorithm used by the OOM: https://unix.stackexchange.com/questions/153585/how-does-the-oom-killer-decide-which-process-to-kill-first
|
||||||
|
|
||||||
|
==== C multithreading
|
||||||
|
|
||||||
|
Added in C11!
|
||||||
|
|
||||||
|
* link:userland/c/atomic.c[]: `atomic_int` and `thrd_create`
|
||||||
|
|
||||||
|
Bibliography:
|
||||||
|
|
||||||
|
* https://stackoverflow.com/questions/3908031/how-to-multithread-c-code/52453354#52453354
|
||||||
|
|
||||||
==== GCC C extensions
|
==== GCC C extensions
|
||||||
|
|
||||||
===== C empty struct
|
===== C empty struct
|
||||||
@@ -12986,8 +12996,6 @@ Programs under link:userland/cpp/[] are examples of https://en.wikipedia.org/wik
|
|||||||
** link:userland/cpp/template.cpp[]: basic example
|
** link:userland/cpp/template.cpp[]: basic example
|
||||||
** link:userland/cpp/template_class_with_static_member.cpp[]: https://stackoverflow.com/questions/3229883/static-member-initialization-in-a-class-template
|
** link:userland/cpp/template_class_with_static_member.cpp[]: https://stackoverflow.com/questions/3229883/static-member-initialization-in-a-class-template
|
||||||
** link:userland/cpp/if_constexpr.cpp[]: C++17 `if constexpr`
|
** link:userland/cpp/if_constexpr.cpp[]: C++17 `if constexpr`
|
||||||
*** https://stackoverflow.com/questions/12160765/if-else-at-compile-time-in-c/54647315#54647315
|
|
||||||
*** https://stackoverflow.com/questions/37617677/implementing-a-compile-time-static-if-logic-for-different-string-types-in-a-co
|
|
||||||
|
|
||||||
[[cpp-multithreading]]
|
[[cpp-multithreading]]
|
||||||
==== C++ multithreading
|
==== C++ multithreading
|
||||||
@@ -12995,6 +13003,8 @@ Programs under link:userland/cpp/[] are examples of https://en.wikipedia.org/wik
|
|||||||
* https://en.cppreference.com/w/cpp/header/thread[`<thread>`]
|
* https://en.cppreference.com/w/cpp/header/thread[`<thread>`]
|
||||||
** link:userland/cpp/count.cpp[] Exemplifies: `std::this_thread::sleep_for`
|
** link:userland/cpp/count.cpp[] Exemplifies: `std::this_thread::sleep_for`
|
||||||
** link:userland/cpp/thread_hardware_concurrency.cpp[] `std::thread::hardware_concurrency`
|
** link:userland/cpp/thread_hardware_concurrency.cpp[] `std::thread::hardware_concurrency`
|
||||||
|
** link:userland/cpp/thread_get_id.cpp[] `std::thread::get_id`
|
||||||
|
** link:userland/cpp/thread_return_value.cpp[]: how to return a value from a thread
|
||||||
* https://en.cppreference.com/w/cpp/header/atomic[`<atomic>`]: <<cpp17>> 32 "Atomic operations library"
|
* https://en.cppreference.com/w/cpp/header/atomic[`<atomic>`]: <<cpp17>> 32 "Atomic operations library"
|
||||||
** link:userland/cpp/atomic.cpp[]
|
** link:userland/cpp/atomic.cpp[]
|
||||||
|
|
||||||
@@ -13093,6 +13103,7 @@ Bibliography: https://stackoverflow.com/questions/6988487/what-does-the-brk-syst
|
|||||||
The following sections are related to multithreading in userland:
|
The following sections are related to multithreading in userland:
|
||||||
|
|
||||||
* language topics:
|
* language topics:
|
||||||
|
** <<c-multithreading>>
|
||||||
** <<cpp-multithreading>>
|
** <<cpp-multithreading>>
|
||||||
** <<pthreads>>
|
** <<pthreads>>
|
||||||
* ISA topics:
|
* ISA topics:
|
||||||
|
|||||||
@@ -475,6 +475,7 @@ path_properties_tuples = (
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
'abort.c': {'signal_received': signal.Signals.SIGABRT},
|
'abort.c': {'signal_received': signal.Signals.SIGABRT},
|
||||||
|
'atomic.c': {'baremetal': False},
|
||||||
'assert_fail.c': {'signal_received': signal.Signals.SIGABRT},
|
'assert_fail.c': {'signal_received': signal.Signals.SIGABRT},
|
||||||
# This has complex failure modes, too hard to assert.
|
# This has complex failure modes, too hard to assert.
|
||||||
'smash_stack.c': {'skip_run_unclassified': True},
|
'smash_stack.c': {'skip_run_unclassified': True},
|
||||||
@@ -483,7 +484,6 @@ path_properties_tuples = (
|
|||||||
'false.c': {'exit_status': 1},
|
'false.c': {'exit_status': 1},
|
||||||
'file_write_read.c': {'baremetal': False},
|
'file_write_read.c': {'baremetal': False},
|
||||||
'getchar.c': {'interactive': True},
|
'getchar.c': {'interactive': True},
|
||||||
'infinite_loop.c': {'test_run_args': {'userland_args': '1 10'}},
|
|
||||||
'malloc_max.c': {'disrupts_system': True},
|
'malloc_max.c': {'disrupts_system': True},
|
||||||
'return1.c': {'exit_status': 1},
|
'return1.c': {'exit_status': 1},
|
||||||
'return2.c': {'exit_status': 2},
|
'return2.c': {'exit_status': 2},
|
||||||
|
|||||||
50
userland/c/atomic.c
Normal file
50
userland/c/atomic.c
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/* https://cirosantilli.com/linux-kernel-module-cheat#c-multithreading */
|
||||||
|
|
||||||
|
#if __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__)
|
||||||
|
#include <stdatomic.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <threads.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
atomic_int acnt;
|
||||||
|
int cnt;
|
||||||
|
size_t niters;
|
||||||
|
|
||||||
|
int f(void *thr_data) {
|
||||||
|
(void)thr_data;
|
||||||
|
for (size_t i = 0; i < niters; ++i) {
|
||||||
|
++cnt;
|
||||||
|
++acnt;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
#if __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__)
|
||||||
|
size_t nthreads;
|
||||||
|
thrd_t *threads;
|
||||||
|
if (argc > 1) {
|
||||||
|
nthreads = strtoull(argv[1], NULL, 0);
|
||||||
|
} else {
|
||||||
|
nthreads = 2;
|
||||||
|
}
|
||||||
|
if (argc > 2) {
|
||||||
|
niters = strtoull(argv[2], NULL, 0);
|
||||||
|
} else {
|
||||||
|
niters = 10;
|
||||||
|
}
|
||||||
|
threads = malloc(sizeof(thrd_t) * nthreads);
|
||||||
|
for(size_t i = 0; i < nthreads; ++i)
|
||||||
|
thrd_create(threads + i, f, NULL);
|
||||||
|
for(size_t i = 0; i < nthreads; ++i)
|
||||||
|
thrd_join(threads[i], NULL);
|
||||||
|
free(threads);
|
||||||
|
printf("atomic %u\n", acnt);
|
||||||
|
printf("non-atomic %u\n", cnt);
|
||||||
|
#else
|
||||||
|
(void)argc;
|
||||||
|
(void)argv;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
* Loop and print an integer whenever a period is reached:
|
* Loop and print an integer whenever a period is reached:
|
||||||
*
|
*
|
||||||
* ....
|
* ....
|
||||||
* ./infinite_loop [period=100000000 [max=0]]
|
* ./loop.out [max=10 [period=1]]
|
||||||
* ....
|
* ....
|
||||||
*
|
*
|
||||||
* * period: period for printing integers to stdout
|
* * period: period for printing integers to stdout
|
||||||
@@ -19,27 +19,25 @@
|
|||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
uintmax_t i, j, period, max;
|
uintmax_t i, j, period, max;
|
||||||
int max_given;
|
|
||||||
if (argc > 1) {
|
if (argc > 1) {
|
||||||
period = strtoumax(argv[1], NULL, 10);
|
max = strtoumax(argv[1], NULL, 10);
|
||||||
} else {
|
} else {
|
||||||
period = 100000000;
|
max = 10;
|
||||||
}
|
}
|
||||||
if (argc > 2) {
|
if (argc > 2) {
|
||||||
max = strtoumax(argv[2], NULL, 10);
|
period = strtoumax(argv[2], NULL, 10);
|
||||||
max_given = 1;
|
|
||||||
} else {
|
} else {
|
||||||
max_given = 0;
|
period = 1;
|
||||||
}
|
}
|
||||||
i = 0;
|
i = 0;
|
||||||
j = 0;
|
j = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
i++;
|
|
||||||
if (period != 0 && i % period == 0) {
|
if (period != 0 && i % period == 0) {
|
||||||
printf("%ju\n", j);
|
printf("%ju\n", j);
|
||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
if (max_given && i == max)
|
i++;
|
||||||
|
if (i == max)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -79,7 +79,7 @@ int main(int argc, char **argv) {
|
|||||||
if (argc > 2) {
|
if (argc > 2) {
|
||||||
niters = std::stoull(argv[2], NULL, 0);
|
niters = std::stoull(argv[2], NULL, 0);
|
||||||
} else {
|
} else {
|
||||||
niters = 10000;
|
niters = 10;
|
||||||
}
|
}
|
||||||
std::vector<std::thread> threads(nthreads);
|
std::vector<std::thread> threads(nthreads);
|
||||||
for (size_t i = 0; i < nthreads; ++i)
|
for (size_t i = 0; i < nthreads; ++i)
|
||||||
|
|||||||
29
userland/cpp/thread_get_id.cpp
Normal file
29
userland/cpp/thread_get_id.cpp
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
// https://cirosantilli.com/linux-kernel-module-cheat#cpp-multithreading
|
||||||
|
//
|
||||||
|
// Spawn some threads and print their ID.
|
||||||
|
//
|
||||||
|
// On Ubuntu 19.04, they ar large possibly non-consecutive numbers.
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
std::mutex mutex;
|
||||||
|
|
||||||
|
void myfunc(int i) {
|
||||||
|
mutex.lock();
|
||||||
|
std::cout << i << " " << std::this_thread::get_id() << std::endl;
|
||||||
|
mutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
std::cout << "main " << std::this_thread::get_id() << std::endl;
|
||||||
|
std::vector<std::thread> threads;
|
||||||
|
for (unsigned int i = 0; i < 4; ++i) {
|
||||||
|
threads.push_back(std::thread(myfunc, i));
|
||||||
|
}
|
||||||
|
for (auto& thread : threads) {
|
||||||
|
thread.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
// https://cirosantilli.com/linux-kernel-module-cheat#cpp-multithreading
|
||||||
|
//
|
||||||
// http://stackoverflow.com/questions/150355/programmatically-find-the-number-of-cores-on-a-machine
|
// http://stackoverflow.com/questions/150355/programmatically-find-the-number-of-cores-on-a-machine
|
||||||
//
|
//
|
||||||
// Not affected by taskset: https://stackoverflow.com/questions/1006289/how-to-find-out-the-number-of-cpus-using-python/55423170#55423170
|
// Not affected by taskset: https://stackoverflow.com/questions/1006289/how-to-find-out-the-number-of-cpus-using-python/55423170#55423170
|
||||||
|
|||||||
61
userland/cpp/thread_return_value.cpp
Normal file
61
userland/cpp/thread_return_value.cpp
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
// http://stackoverflow.com/questions/7686939/c-simple-return-value-from-stdthread
|
||||||
|
// http://stackoverflow.com/questions/28950835/c-error-no-type-named-type-in-class-stdresult-ofvoid-stdunordered
|
||||||
|
// http://stackoverflow.com/questions/21048906/stdthread-pass-by-reference-calls-copy-constructor
|
||||||
|
// http://stackoverflow.com/questions/8299545/passing-arguments-to-thread-function
|
||||||
|
// http://stackoverflow.com/questions/5116756/difference-between-pointer-and-reference-as-thread-parameter
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <future>
|
||||||
|
#include <iostream>
|
||||||
|
#include <thread>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
int myfunc(int i) {
|
||||||
|
return i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void myfunc_reference(int& i) {
|
||||||
|
i = myfunc(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
unsigned int nthreads = 4;
|
||||||
|
std::vector<int> inputs{1, 2, 3, 4};
|
||||||
|
std::vector<int> outputs_expect{2, 3, 4, 5};
|
||||||
|
|
||||||
|
// future and sync. Nirvana. When you are not fighting to death with types:
|
||||||
|
// https://stackoverflow.com/questions/10620300/can-stdasync-be-use-with-template-functions
|
||||||
|
{
|
||||||
|
std::vector<std::future<int>> futures(nthreads);
|
||||||
|
std::vector<int> outputs(nthreads);
|
||||||
|
for (decltype(futures)::size_type i = 0; i < nthreads; ++i) {
|
||||||
|
futures[i] = std::async(
|
||||||
|
myfunc,
|
||||||
|
inputs[i]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
for (decltype(futures)::size_type i = 0; i < nthreads; ++i) {
|
||||||
|
outputs[i] = futures[i].get();
|
||||||
|
}
|
||||||
|
assert(outputs_expect == outputs);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reference arguments.
|
||||||
|
//
|
||||||
|
// Annoying because requires:
|
||||||
|
//
|
||||||
|
// - wrapping the return function to accept references
|
||||||
|
// - keeping an array of outputs
|
||||||
|
// - std::ref
|
||||||
|
{
|
||||||
|
std::vector<std::thread> threads(nthreads);
|
||||||
|
std::vector<int> inouts(inputs);
|
||||||
|
for (decltype(threads)::size_type i = 0; i < nthreads; ++i) {
|
||||||
|
threads[i] = std::thread(myfunc_reference, std::ref(inouts[i]));
|
||||||
|
}
|
||||||
|
for (auto& thread : threads) {
|
||||||
|
thread.join();
|
||||||
|
}
|
||||||
|
assert(outputs_expect == inouts);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user