├── .gitignore
├── python
├── .gitignore
├── demo25_atomic.py
├── demo24_volatile.py
├── demo10_yield.py
├── exer08_exec_service_itask.py
├── demo01_hello.py
├── demoex_timer.py
├── demo04_sleep.py
├── demo02a_join.py
├── demo01ex_name.py
├── demo03b_pass_arg.py
├── demo06_list_threads.py
├── demo12a_race_condition.py
├── demo00.py
├── demo03a_pass_arg.py
├── demo12b01_data_race_single.py
├── demo02b_join.py
├── demo11c01_exec_service.py
├── demo09_detach.py
├── demo17b_reentrant_lock.py
├── demo11a_exec_service.py
├── demo07_terminate.py
├── demo11c02_exec_service.py
├── demo21a01_condition_variable.py
├── demo08a_return_value.py
├── demo08b_return_value.py
├── demo17a_reentrant_lock.py
├── demo23a_thread_local.py
├── demo12c01_race_cond_data_race.py
├── demo15a_deadlock.py
├── demo17c_reentrant_lock.py
├── demo11b_exec_service.py
├── demo21a02_condition_variable.py
├── demo21a03_condition_variable.py
├── demo12c02_race_cond_data_race.py
├── exer04_dining_philosophers.py
├── demo14_synchronized_block.py
├── demo05_id.py
├── exer02a01_producer_consumer.py
├── demo18a01_barrier.py
├── demo22a_blocking_queue.py
├── demo13a_mutex.py
├── demo20a01_semaphore.py
├── demo12b02_data_race_multi.py
├── exer01a_max_div.py
├── demo18a03_barrier.py
├── exer02a02_producer_consumer.py
├── demo18a02_barrier.py
├── demo23b_thread_local.py
├── exer02a03_producer_consumer.py
├── demo18b01_latch.py
├── demo15b_deadlock.py
├── demo20a02_semaphore.py
├── demo22b_blocking_queue.py
├── exer02a04_producer_consumer.py
├── demo20a03_semaphore_deadlock.py
├── demo20b_semaphore.py
├── demo18b02_latch.py
├── demo16_monitor.py
└── demoex_event.py
├── cpp
├── .gitignore
├── cpp-boost
│ ├── exer08-exec-service-itask.hpp
│ ├── exer05-util.hpp
│ ├── demo01a01-hello.cpp
│ ├── demo01a02-hello.cpp
│ ├── demo02-join.cpp
│ ├── demo01b-hello-functor.cpp
│ ├── demo00.cpp
│ ├── demo03b-pass-arg.cpp
│ ├── demo01b-hello-class03.cpp
│ ├── demo04a-sleep.cpp
│ ├── demo01b-hello-class01.cpp
│ ├── demo12a-race-condition.cpp
│ ├── demo05-id.cpp
│ ├── demo06a-list-threads.cpp
│ ├── demo24-volatile.cpp
│ ├── demo06c-list-threads.cpp
│ ├── demo07-terminate.cpp
│ ├── demo15a-deadlock.cpp
│ ├── demo25a-atomic.cpp
│ ├── demo01b-hello-class02.cpp
│ ├── demo25b-atomic.cpp
│ ├── demo09-detach.cpp
│ ├── demo03c-pass-arg.cpp
│ ├── demo17a-reentrant-lock.cpp
│ ├── demo12b01-data-race-single.cpp
│ ├── demo06b-list-threads.cpp
│ ├── demo21a01-condition-variable.cpp
│ ├── demo12c01-race-cond-data-race.cpp
│ ├── demo13a-mutex.cpp
│ ├── demo03a-pass-arg.cpp
│ ├── demo08-return-value.cpp
│ ├── demo11a-exec-service.cpp
│ ├── demo13c-mutex-trylock.cpp
│ ├── demo10-yield.cpp
│ ├── demo11b-exec-service.cpp
│ ├── demo13b01-mutex.cpp
│ ├── demo17b-reentrant-lock.cpp
│ ├── demo23a-thread-local.cpp
│ └── demo21a03-condition-variable.cpp
├── cpp-std
│ ├── exer08-exec-service-itask.hpp
│ ├── exer05-util.hpp
│ ├── demo01c-hello-lambda.cpp
│ ├── demo01a01-hello.cpp
│ ├── demo01a02-hello.cpp
│ ├── demo02-join.cpp
│ ├── demo03b-pass-arg.cpp
│ ├── demo01b-hello-functor.cpp
│ ├── demo00.cpp
│ ├── demo01b-hello-class01.cpp
│ ├── demo04a-sleep.cpp
│ ├── demo01b-hello-class02.cpp
│ ├── demo01b-hello-class03.cpp
│ ├── demo06a-list-threads.cpp
│ ├── demo05-id.cpp
│ ├── demo24-volatile.cpp
│ ├── demo23a01-thread-local.cpp
│ ├── demo07-terminate.cpp
│ ├── demo12a-race-condition.cpp
│ ├── demo09-detach.cpp
│ ├── demo15a-deadlock.cpp
│ ├── demo25a-atomic.cpp
│ ├── demo17a-reentrant-lock.cpp
│ ├── demo25b-atomic.cpp
│ ├── demo12b01-data-race-single.cpp
│ ├── demo06b-list-threads.cpp
│ ├── demo10-yield.cpp
│ ├── demo12c01-race-cond-data-race.cpp
│ ├── demo13a-mutex.cpp
│ ├── demo21a01-condition-variable.cpp
│ ├── demo08a-return-value.cpp
│ ├── demo03a-pass-arg.cpp
│ ├── demo23a02-thread-local.cpp
│ ├── demo08c-return-value.cpp
│ ├── demo13c-mutex-trylock.cpp
│ ├── demo08b-return-value.cpp
│ ├── demo17b-reentrant-lock.cpp
│ └── demo12b02-data-race-multi.cpp
└── cpp-pthread
│ ├── exer08-exec-service-itask.hpp
│ ├── demo04-sleep.cpp
│ ├── demo02-join.cpp
│ ├── demo01-hello.cpp
│ ├── demo00.cpp
│ ├── demo24-volatile.cpp
│ ├── exer05-util.hpp
│ ├── demo07b-terminate.cpp
│ ├── demo23a-thread-local.cpp
│ ├── demo03a02-pass-arg.cpp
│ ├── demo05-id.cpp
│ ├── demo09b-detach.cpp
│ ├── demo07a-terminate.cpp
│ ├── demo08b-return-value.cpp
│ ├── demo25a-atomic.c
│ ├── demo12b01-data-race-single.cpp
│ ├── demoex-signal.cpp
│ ├── demo08a-return-value.cpp
│ ├── demo06a-list-threads.cpp
│ ├── demo12bex-data-race-fork.cpp
│ ├── demo03a01-pass-arg.cpp
│ ├── demo12a-race-condition.cpp
│ ├── demo03b01-pass-arg.cpp
│ ├── demo03b02-pass-arg.cpp
│ ├── demo06b-list-threads.cpp
│ ├── demo25b-atomic.c
│ ├── demo10-yield.cpp
│ ├── demo12c01-race-cond-data-race.cpp
│ ├── demo15a-deadlock.cpp
│ ├── demo11b-exec-service.cpp
│ ├── demo12c02-race-cond-data-race.cpp
│ ├── demo13a-mutex.cpp
│ └── demo09a-detach.cpp
├── csharp
├── .gitignore
├── IRunnable.cs
├── Program.cs
├── multithreading.csproj
├── demo
│ ├── demo01b02-hello.cs
│ ├── demo03d-pass-arg.cs
│ ├── demo04-sleep.cs
│ ├── demo06b-list-threads.cs
│ ├── demo02a-join.cs
│ ├── demo03a-pass-arg.cs
│ ├── demo00-intro.cs
│ ├── demo01a-hello.cs
│ ├── demo01b01-hello.cs
│ ├── demo01ex-name.cs
│ ├── demo02b-join.cs
│ ├── demo05-id.cs
│ ├── demo03c-pass-arg.cs
│ ├── demo12a-race-condition.cs
│ ├── demo24-volatile.cs
│ ├── demo09-detach.cs
│ ├── demo10-yield.cs
│ ├── demo11c-exec-service.cs
│ ├── demo08a-return-value.cs
│ ├── demo12b01-data-race-single.cs
│ ├── demo17a-reentrant-lock.cs
│ ├── demo25a-atomic.cs
│ ├── demo07-terminate.cs
│ ├── demo11a01-exec-service.cs
│ ├── demo11a03-exec-service.cs
│ ├── demo25b-atomic.cs
│ ├── demo11b02-exec-service-parallel.cs
│ ├── demo12c02-race-cond-data-race.cs
│ ├── demo15a-deadlock.cs
│ ├── demo08b-return-value.cs
│ ├── demo11a02-exec-service.cs
│ ├── demo12c01-race-cond-data-race.cs
│ ├── demo03b-pass-arg.cs
│ ├── demo12b02-data-race-multi.cs
│ ├── demo11b01-exec-service-parallel.cs
│ ├── demo06a-list-threads.cs
│ ├── demo21a03-condition-variable.cs
│ └── demo11a05-exec-service.cs
└── demoex
│ ├── demoex-async-future-a03.cs
│ ├── demoex-async-future-a01.cs
│ ├── demoex-async-future-a02.cs
│ ├── demoex-async-future-c01.cs
│ ├── demoex-async-future-c02.cs
│ ├── demoex-async-future-a05.cs
│ └── demoex-async-future-a04.cs
├── js-nodejs
├── .gitignore
├── demo01b-hello-worker.js
├── package.json
├── demo01b-hello.js
├── demo12b01-data-race-single.js
├── demo00.js
├── exerex-userhash-util.js
├── demo01a-hello.js
└── exer01a-max-div.js
├── java
├── .gitignore
├── README.md
└── src
│ ├── demoex
│ └── async
│ │ ├── AppA.java
│ │ └── AppC02.java
│ ├── demo13_mutex
│ └── AppA.java
│ ├── demo01_hello
│ ├── AppB03.java
│ ├── AppC02.java
│ ├── AppC01.java
│ ├── AppA02.java
│ ├── AppB02.java
│ ├── AppA01.java
│ ├── AppB01.java
│ └── AppExtra.java
│ ├── demo03_pass_arg
│ ├── AppC.java
│ ├── AppB.java
│ └── AppA.java
│ ├── demo06_list_threads
│ ├── AppB02.java
│ ├── AppB01.java
│ └── AppA.java
│ ├── demo05_id
│ └── App.java
│ ├── demo00_intro
│ └── App.java
│ ├── demo04_sleep
│ └── App.java
│ ├── demo12_race_condition
│ ├── AppA.java
│ ├── AppC02.java
│ └── AppB01.java
│ ├── demo02_join
│ ├── AppB.java
│ └── AppA.java
│ ├── demo24_volatile
│ └── App.java
│ ├── demo17_reentrant_lock
│ ├── AppA01.java
│ └── AppB01.java
│ ├── demo09_detach
│ └── App.java
│ ├── demo08_return_value
│ ├── AppB.java
│ └── AppA.java
│ ├── demo10_yield
│ └── App.java
│ ├── demo07_terminate
│ ├── AppA.java
│ └── AppB.java
│ ├── demo11_exec_service
│ ├── AppA.java
│ └── AppC02.java
│ ├── demo25_atomic
│ ├── AppA.java
│ └── AppB.java
│ └── demo23_thread_local
│ └── AppA02.java
└── old
├── cppstd-ex-thread-pool-deadlock.zip
├── cppstd-reentrant-lock-b.cpp
└── cppstd-reentrant-lock-a.cpp
/.gitignore:
--------------------------------------------------------------------------------
1 | .vscode/
2 |
--------------------------------------------------------------------------------
/python/.gitignore:
--------------------------------------------------------------------------------
1 | __pycache__/
2 |
--------------------------------------------------------------------------------
/cpp/.gitignore:
--------------------------------------------------------------------------------
1 | a
2 | a.out
3 | tmp*
4 |
--------------------------------------------------------------------------------
/csharp/.gitignore:
--------------------------------------------------------------------------------
1 | bin/
2 | obj/
3 | .vs/
4 |
--------------------------------------------------------------------------------
/js-nodejs/.gitignore:
--------------------------------------------------------------------------------
1 | /package-lock.json
2 | /node_modules/
--------------------------------------------------------------------------------
/java/.gitignore:
--------------------------------------------------------------------------------
1 | /bin/
2 | /build/
3 | /dist/
4 | .classpath
5 | .project
6 |
--------------------------------------------------------------------------------
/js-nodejs/demo01b-hello-worker.js:
--------------------------------------------------------------------------------
1 | console.log('Hello from example thread');
2 |
--------------------------------------------------------------------------------
/csharp/IRunnable.cs:
--------------------------------------------------------------------------------
1 | interface IRunnable
2 | {
3 | public abstract void run();
4 | }
5 |
--------------------------------------------------------------------------------
/python/demo25_atomic.py:
--------------------------------------------------------------------------------
1 | '''
2 | ATOMIC ACCESS
3 | The atomic operation syntax in Python is not supported by default.
4 | '''
5 |
--------------------------------------------------------------------------------
/python/demo24_volatile.py:
--------------------------------------------------------------------------------
1 | '''
2 | THE VOLATILE KEYWORD
3 | The "volatile" keyword in Python are not supported by default.
4 | '''
5 |
--------------------------------------------------------------------------------
/old/cppstd-ex-thread-pool-deadlock.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thanhit95/multi-threading/HEAD/old/cppstd-ex-thread-pool-deadlock.zip
--------------------------------------------------------------------------------
/csharp/Program.cs:
--------------------------------------------------------------------------------
1 | class Program
2 | {
3 | static void Main(string[] args)
4 | {
5 | new Demo00().run();
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/python/demo10_yield.py:
--------------------------------------------------------------------------------
1 | '''
2 | THREAD YIELDING
3 |
4 | I think that thread yielding does not make sense in Python.
5 | No demo available.
6 | '''
7 |
--------------------------------------------------------------------------------
/python/exer08_exec_service_itask.py:
--------------------------------------------------------------------------------
1 | from abc import ABC, abstractmethod
2 |
3 |
4 | class ITask(ABC):
5 | @abstractmethod
6 | def run(self):
7 | pass
8 |
--------------------------------------------------------------------------------
/java/README.md:
--------------------------------------------------------------------------------
1 | # JAVA MULTITHREADING
2 |
3 | ## DESCRIPTION
4 |
5 | Multithreading in Java.
6 |
7 | ## PROJECT SPECIFICATIONS
8 |
9 | WARNING: Java-17 features.
10 |
--------------------------------------------------------------------------------
/js-nodejs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "module",
3 | "dependencies": {
4 | "@types/node": "^18.7.2",
5 | "async-mutex": "^0.3.2",
6 | "express": "^4.18.1",
7 | "piscina": "^3.2.0"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/csharp/multithreading.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net6.0
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/python/demo01_hello.py:
--------------------------------------------------------------------------------
1 | '''
2 | HELLO WORLD VERSION MULTITHREADING
3 | '''
4 |
5 | import threading
6 |
7 |
8 |
9 | def do_task():
10 | print('Hello from example thread')
11 |
12 |
13 |
14 | th = threading.Thread(target=do_task)
15 | th.start()
16 |
17 | print('Hello from main thread')
18 |
--------------------------------------------------------------------------------
/python/demoex_timer.py:
--------------------------------------------------------------------------------
1 | '''
2 | TIMER OBJECTS
3 | '''
4 |
5 | import time
6 | import threading
7 |
8 |
9 |
10 | def func_time_out():
11 | print('Time out!!!')
12 |
13 |
14 |
15 | threading.Timer(10, func_time_out).start()
16 |
17 | for i in range(9, -1, -1):
18 | print(i)
19 | time.sleep(1)
20 |
--------------------------------------------------------------------------------
/cpp/cpp-boost/exer08-exec-service-itask.hpp:
--------------------------------------------------------------------------------
1 | #ifndef _MY_EXEC_SERVICE_ITASK_HPP_
2 | #define _MY_EXEC_SERVICE_ITASK_HPP_
3 |
4 |
5 |
6 | // interface ITask
7 | class ITask {
8 | public:
9 | virtual ~ITask() { }
10 | virtual void run() = 0;
11 | };
12 |
13 |
14 |
15 | #endif // _MY_EXEC_SERVICE_ITASK_HPP_
16 |
--------------------------------------------------------------------------------
/cpp/cpp-std/exer08-exec-service-itask.hpp:
--------------------------------------------------------------------------------
1 | #ifndef _MY_EXEC_SERVICE_ITASK_HPP_
2 | #define _MY_EXEC_SERVICE_ITASK_HPP_
3 |
4 |
5 |
6 | // interface ITask
7 | class ITask {
8 | public:
9 | virtual ~ITask() = default;
10 | virtual void run() = 0;
11 | };
12 |
13 |
14 |
15 | #endif // _MY_EXEC_SERVICE_ITASK_HPP_
16 |
--------------------------------------------------------------------------------
/java/src/demoex/async/AppA.java:
--------------------------------------------------------------------------------
1 | /*
2 | * ASYNCHRONOUS PROGRAMMING WITH THE FUTURE/TASK
3 | */
4 |
5 | package demoex.async;
6 |
7 |
8 |
9 | public class AppA {
10 |
11 | public static void main(String[] args) {
12 | System.out.println("Please review demo: Thread pool, version C");
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/cpp/cpp-pthread/exer08-exec-service-itask.hpp:
--------------------------------------------------------------------------------
1 | #ifndef _MY_EXEC_SERVICE_ITASK_HPP_
2 | #define _MY_EXEC_SERVICE_ITASK_HPP_
3 |
4 |
5 |
6 | // interface ITask
7 | class ITask {
8 | public:
9 | virtual ~ITask() = default;
10 | virtual void run() = 0;
11 | };
12 |
13 |
14 |
15 | #endif // _MY_EXEC_SERVICE_ITASK_HPP_
16 |
--------------------------------------------------------------------------------
/python/demo04_sleep.py:
--------------------------------------------------------------------------------
1 | '''
2 | SLEEP
3 | '''
4 |
5 | import time
6 | import threading
7 |
8 |
9 |
10 | def do_task():
11 | print('foo is sleeping')
12 | time.sleep(3)
13 | print('foo wakes up')
14 |
15 |
16 |
17 | th_foo = threading.Thread(target=do_task)
18 |
19 | th_foo.start()
20 | th_foo.join()
21 |
22 | print('Good bye')
23 |
--------------------------------------------------------------------------------
/java/src/demo13_mutex/AppA.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MUTEXES
3 | */
4 |
5 | package demo13_mutex;
6 |
7 |
8 |
9 | public class AppA {
10 |
11 | public static void main(String[] args) {
12 | /*
13 | * Unfortunately, Java does not support the mutex feature by default.
14 | * You can use a binary semaphore as a mutex.
15 | */
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/python/demo02a_join.py:
--------------------------------------------------------------------------------
1 | '''
2 | THREAD JOINS
3 | '''
4 |
5 | import threading
6 |
7 |
8 |
9 | def do_heavy_task():
10 | # Do a heavy task, which takes a little time
11 | for _ in range(0, 2 * 10**8):
12 | pass
13 |
14 | print('Done!')
15 |
16 |
17 |
18 | th = threading.Thread(target=do_heavy_task)
19 |
20 | th.start()
21 | th.join()
22 |
23 | print('Good bye!')
24 |
--------------------------------------------------------------------------------
/cpp/cpp-boost/exer05-util.hpp:
--------------------------------------------------------------------------------
1 | #ifndef _EXER05_UTIL_HPP_
2 | #define _EXER05_UTIL_HPP_
3 |
4 |
5 |
6 | void getScalarProduct(double const* u, double const* v, int sizeVector, double* res) {
7 | double sum = 0;
8 |
9 | for (int i = sizeVector - 1; i >= 0; --i) {
10 | sum += u[i] * v[i];
11 | }
12 |
13 | (*res) = sum;
14 | }
15 |
16 |
17 |
18 | #endif // _EXER05_UTIL_HPP_
19 |
--------------------------------------------------------------------------------
/cpp/cpp-std/exer05-util.hpp:
--------------------------------------------------------------------------------
1 | #ifndef _EXER05_UTIL_HPP_
2 | #define _EXER05_UTIL_HPP_
3 |
4 |
5 |
6 | void getScalarProduct(double const* u, double const* v, int sizeVector, double* res) {
7 | double sum = 0;
8 |
9 | for (int i = sizeVector - 1; i >= 0; --i) {
10 | sum += u[i] * v[i];
11 | }
12 |
13 | (*res) = sum;
14 | }
15 |
16 |
17 |
18 | #endif // _EXER05_UTIL_HPP_
19 |
--------------------------------------------------------------------------------
/python/demo01ex_name.py:
--------------------------------------------------------------------------------
1 | '''
2 | HELLO WORLD VERSION MULTITHREADING
3 | Getting thread's name
4 | '''
5 |
6 | import threading
7 |
8 |
9 |
10 | def do_task():
11 | print(f'My name is {threading.current_thread().name}')
12 |
13 |
14 |
15 | th_foo = threading.Thread(target=do_task, name='foo')
16 | th_bar = threading.Thread(target=do_task, name='bar')
17 | th_foo.start()
18 | th_bar.start()
19 |
--------------------------------------------------------------------------------
/python/demo03b_pass_arg.py:
--------------------------------------------------------------------------------
1 | '''
2 | PASSING ARGUMENTS
3 | Version B: Using lambdas
4 | '''
5 |
6 | import threading
7 |
8 |
9 |
10 | def do_task(a: int, b: float, c: str):
11 | print(f'{a} {b} {c}')
12 |
13 |
14 |
15 | th_foo = threading.Thread(target=lambda:do_task(1, 2, 'red'))
16 | th_bar = threading.Thread(target=lambda:do_task(3, 4, 'blue'))
17 |
18 | th_foo.start()
19 | th_bar.start()
20 |
--------------------------------------------------------------------------------
/python/demo06_list_threads.py:
--------------------------------------------------------------------------------
1 | '''
2 | LIST OF MULTIPLE THREADS
3 | '''
4 |
5 | import time
6 | import threading
7 |
8 |
9 |
10 | def do_task(index):
11 | time.sleep(0.5)
12 | print(index, end='')
13 |
14 |
15 |
16 | NUM_THREADS = 5
17 | lstth = []
18 |
19 | for i in range(NUM_THREADS):
20 | lstth.append(threading.Thread( target=do_task, args=(i,) ))
21 |
22 | for th in lstth:
23 | th.start()
24 |
--------------------------------------------------------------------------------
/python/demo12a_race_condition.py:
--------------------------------------------------------------------------------
1 | '''
2 | RACE CONDITIONS
3 | '''
4 |
5 | import time
6 | import threading
7 |
8 |
9 |
10 | def do_task(index: int):
11 | time.sleep(1)
12 | print(index, end='')
13 |
14 |
15 |
16 | NUM_THREADS = 4
17 | lstth = []
18 |
19 | for i in range(NUM_THREADS):
20 | lstth.append(threading.Thread( target=do_task, args=(i,) ))
21 |
22 | for th in lstth:
23 | th.start()
24 |
--------------------------------------------------------------------------------
/python/demo00.py:
--------------------------------------------------------------------------------
1 | '''
2 | INTRODUCTION TO MULTITHREADING
3 | You should try running this app several times and see results.
4 | '''
5 |
6 | import threading
7 |
8 |
9 |
10 | def do_task():
11 | for _ in range(300):
12 | print('B', end='')
13 |
14 |
15 |
16 | th = threading.Thread(target=do_task)
17 | th.start()
18 |
19 | for _ in range(300):
20 | print('A', end='')
21 |
22 | th.join()
23 | print()
24 |
--------------------------------------------------------------------------------
/python/demo03a_pass_arg.py:
--------------------------------------------------------------------------------
1 | '''
2 | PASSING ARGUMENTS
3 | Version A: Using the Thread's constructor
4 | '''
5 |
6 | import threading
7 |
8 |
9 |
10 | def do_task(a: int, b: float, c: str):
11 | print(f'{a} {b} {c}')
12 |
13 |
14 |
15 | th_foo = threading.Thread(target=do_task, args=(1, 2, 'red'))
16 | th_bar = threading.Thread(target=do_task, args=(3, 4, 'blue'))
17 |
18 | th_foo.start()
19 | th_bar.start()
20 |
--------------------------------------------------------------------------------
/cpp/cpp-std/demo01c-hello-lambda.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | HELLO WORLD VERSION MULTITHREADING
3 | Version C: Using lambdas
4 | */
5 |
6 |
7 | #include
8 | #include
9 | #include
10 | using namespace std;
11 |
12 |
13 |
14 | int main() {
15 | auto doTask = [](string message) {
16 | cout << message << endl;
17 | };
18 |
19 | std::thread th(doTask, "Good day");
20 |
21 | th.join();
22 | return 0;
23 | }
24 |
--------------------------------------------------------------------------------
/cpp/cpp-std/demo01a01-hello.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | HELLO WORLD VERSION MULTITHREADING
3 | Version A01: Using functions
4 | */
5 |
6 |
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | void doTask() {
14 | cout << "Hello from example thread" << endl;
15 | }
16 |
17 |
18 |
19 | int main() {
20 | std::thread th(&doTask);
21 |
22 | cout << "Hello from main thread" << endl;
23 |
24 | th.join();
25 | return 0;
26 | }
27 |
--------------------------------------------------------------------------------
/python/demo12b01_data_race_single.py:
--------------------------------------------------------------------------------
1 | '''
2 | DATA RACES
3 | Version 01: Without multithreading
4 | '''
5 |
6 |
7 |
8 | def get_result(n: int):
9 | a = [False] * (n + 1)
10 |
11 | for i in range(1, n + 1):
12 | if i % 2 == 0 or i % 3 == 0:
13 | a[i] = True
14 |
15 | res = a.count(True)
16 | return res
17 |
18 |
19 |
20 | N = 8
21 | result = get_result(N)
22 | print('Number of integers that are divisible by 2 or 3 is:', result)
23 |
--------------------------------------------------------------------------------
/cpp/cpp-std/demo01a02-hello.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | HELLO WORLD VERSION MULTITHREADING
3 | Version A02: Using functions allowing passing 2 arguments
4 | */
5 |
6 |
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | void doTask(char const* message, int number) {
14 | cout << message << " " << number << endl;
15 | }
16 |
17 |
18 |
19 | int main() {
20 | std::thread th(&doTask, "Good day", 19);
21 | th.join();
22 | return 0;
23 | }
24 |
--------------------------------------------------------------------------------
/csharp/demo/demo01b02-hello.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * HELLO WORLD VERSION MULTITHREADING
3 | * Version B02: Using lambdas
4 | */
5 | using System;
6 | using System.Threading;
7 |
8 |
9 |
10 | class Demo01B02 : IRunnable
11 | {
12 | public void run()
13 | {
14 | Thread th = new Thread(() => Console.WriteLine("Hello from example thread"));
15 |
16 | th.Start();
17 |
18 | Console.WriteLine("Hello from main thread");
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/python/demo02b_join.py:
--------------------------------------------------------------------------------
1 | '''
2 | THREAD JOINS
3 | '''
4 |
5 | import threading
6 |
7 |
8 |
9 | th_foo = threading.Thread(target=lambda:print('foo'))
10 | th_bar = threading.Thread(target=lambda:print('bar'))
11 |
12 | th_foo.start()
13 | th_bar.start()
14 |
15 | # th_foo.join()
16 | # th_bar.join()
17 |
18 | '''
19 | We do not need to call th_foo.join() and th_bar.join().
20 | The reason is main thread will wait for the completion of all threads before app exits.
21 | '''
22 |
--------------------------------------------------------------------------------
/python/demo11c01_exec_service.py:
--------------------------------------------------------------------------------
1 | '''
2 | EXECUTOR SERVICES AND THREAD POOLS
3 | Version C01: The executor service and Future objects
4 | '''
5 |
6 | from concurrent.futures import ThreadPoolExecutor
7 |
8 |
9 |
10 | def get_squared(x):
11 | return x * x
12 |
13 |
14 |
15 | executor = ThreadPoolExecutor(max_workers=1)
16 |
17 | future = executor.submit(get_squared, 7)
18 | # print(future.done())
19 |
20 | print(future.result())
21 |
22 | executor.shutdown(wait=True)
23 |
--------------------------------------------------------------------------------
/cpp/cpp-boost/demo01a01-hello.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | HELLO WORLD VERSION MULTITHREADING
3 | Version A01: Using functions
4 | */
5 |
6 |
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | void doTask() {
14 | cout << "Hello from example thread" << endl;
15 | }
16 |
17 |
18 |
19 | int main() {
20 | boost::thread th(&doTask);
21 |
22 | cout << "Hello from main thread" << endl;
23 |
24 | th.join();
25 | return 0;
26 | }
27 |
--------------------------------------------------------------------------------
/js-nodejs/demo01b-hello.js:
--------------------------------------------------------------------------------
1 | /*
2 | HELLO WORLD VERSION MULTITHREADING
3 | Version B: Using the individual source code files:
4 | - Main thread: demo01b-hello.js
5 | - Worker thread: demo01b-hello-worker.js
6 | */
7 |
8 | import * as path from 'path';
9 | import { Worker, isMainThread } from 'worker_threads';
10 |
11 | const workerFileName = `./${path.parse(import.meta.url).name}-worker.js`;
12 | const worker = new Worker(workerFileName);
13 |
14 | console.log('Hello from main thread');
15 |
--------------------------------------------------------------------------------
/python/demo09_detach.py:
--------------------------------------------------------------------------------
1 | '''
2 | THREAD DETACHING
3 | '''
4 |
5 | import time
6 | import threading
7 |
8 |
9 |
10 | def do_task():
11 | print('foo is starting...')
12 | time.sleep(2)
13 | print('foo is exiting...')
14 |
15 |
16 |
17 | th_foo = threading.Thread(target=do_task, daemon=True)
18 | th_foo.start()
19 |
20 | # If I comment this statement,
21 | # th_foo will be forced into terminating with main thread
22 | time.sleep(3)
23 |
24 | print('Main thread is exiting')
25 |
--------------------------------------------------------------------------------
/cpp/cpp-boost/demo01a02-hello.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | HELLO WORLD VERSION MULTITHREADING
3 | Version A02: Using functions allowing passing 2 arguments
4 | */
5 |
6 |
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | void doTask(char const* message, int number) {
14 | cout << message << " " << number << endl;
15 | }
16 |
17 |
18 |
19 | int main() {
20 | boost::thread th(&doTask, "Good day", 19);
21 | th.join();
22 | return 0;
23 | }
24 |
--------------------------------------------------------------------------------
/python/demo17b_reentrant_lock.py:
--------------------------------------------------------------------------------
1 | '''
2 | REENTRANT LOCKS (RECURSIVE MUTEXES)
3 | Version B: Solving the problem from version A
4 | '''
5 |
6 | import threading
7 |
8 |
9 |
10 | lock = threading.RLock()
11 |
12 |
13 |
14 | def do_task():
15 | with lock:
16 | print('First time acquiring the resource')
17 | with lock:
18 | print('Second time acquiring the resource')
19 |
20 |
21 |
22 | th = threading.Thread(target=do_task)
23 | th.start()
24 | th.join()
25 |
--------------------------------------------------------------------------------
/cpp/cpp-std/demo02-join.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | THREAD JOINS
3 | */
4 |
5 |
6 | #include
7 | #include
8 | using namespace std;
9 |
10 |
11 |
12 | void doHeavyTask() {
13 | // Do a heavy task, which takes a little time
14 | for (int i = 0; i < 2000000000; ++i);
15 |
16 | cout << "Done!" << endl;
17 | }
18 |
19 |
20 |
21 | int main() {
22 | std::thread th(&doHeavyTask);
23 |
24 | th.join();
25 |
26 | cout << "Good bye!" << endl;
27 |
28 | return 0;
29 | }
30 |
--------------------------------------------------------------------------------
/python/demo11a_exec_service.py:
--------------------------------------------------------------------------------
1 | '''
2 | EXECUTOR SERVICES AND THREAD POOLS
3 | Version A: The executor service (of which thread pool) containing a single thread
4 | '''
5 |
6 | from concurrent.futures import ThreadPoolExecutor
7 |
8 |
9 |
10 | def do_task():
11 | print('Hello the Executor Service')
12 |
13 |
14 |
15 | executor = ThreadPoolExecutor(max_workers=1)
16 |
17 | executor.submit(lambda: print('Hello World'))
18 | executor.submit(do_task)
19 |
20 | executor.shutdown(wait=True)
21 |
--------------------------------------------------------------------------------
/java/src/demo01_hello/AppB03.java:
--------------------------------------------------------------------------------
1 | /*
2 | * HELLO WORLD VERSION MULTITHREADING
3 | * Version B03: Using inteface Runnable with lambdas
4 | */
5 |
6 | package demo01_hello;
7 |
8 |
9 |
10 | public class AppB03 {
11 |
12 | public static void main(String[] args) throws InterruptedException {
13 | var th = new Thread(() -> System.out.println("Hello from example thread"));
14 |
15 | th.start();
16 |
17 | System.out.println("Hello from main thread");
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/cpp/cpp-boost/demo02-join.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | THREAD JOINS
3 | */
4 |
5 |
6 | #include
7 | #include
8 | using namespace std;
9 |
10 |
11 |
12 | void doHeavyTask() {
13 | // Do a heavy task, which takes a little time
14 | for (int i = 0; i < 2000000000; ++i);
15 |
16 | cout << "Done!" << endl;
17 | }
18 |
19 |
20 |
21 | int main() {
22 | boost::thread th(&doHeavyTask);
23 |
24 | th.join();
25 |
26 | cout << "Good bye!" << endl;
27 |
28 | return 0;
29 | }
30 |
--------------------------------------------------------------------------------
/python/demo07_terminate.py:
--------------------------------------------------------------------------------
1 | '''
2 | FORCING A THREAD TO TERMINATE (i.e. killing the thread)
3 | Using a flag to notify the thread
4 | '''
5 |
6 | import time
7 | import threading
8 |
9 |
10 |
11 | flag_stop = False
12 |
13 |
14 |
15 | def do_task():
16 | while True:
17 | if flag_stop:
18 | break
19 |
20 | print('Running...')
21 | time.sleep(1)
22 |
23 |
24 |
25 | th = threading.Thread(target=do_task)
26 | th.start()
27 |
28 | time.sleep(3)
29 | flag_stop = True
30 |
--------------------------------------------------------------------------------
/python/demo11c02_exec_service.py:
--------------------------------------------------------------------------------
1 | '''
2 | EXECUTOR SERVICES AND THREAD POOLS
3 | Version C02: The executor service and Future objects
4 | '''
5 |
6 | import time
7 | from concurrent.futures import ThreadPoolExecutor
8 |
9 |
10 |
11 | def get_squared(x):
12 | time.sleep(3)
13 | return x * x
14 |
15 |
16 |
17 | executor = ThreadPoolExecutor(max_workers=1)
18 |
19 | future = executor.submit(get_squared, 7)
20 |
21 | print('Calculating...')
22 | print(future.result())
23 |
24 | executor.shutdown(wait=True)
25 |
--------------------------------------------------------------------------------
/cpp/cpp-std/demo03b-pass-arg.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | PASSING ARGUMENTS
3 | Version B: Passing constant references
4 | */
5 |
6 |
7 | #include
8 | #include
9 | #include
10 | using namespace std;
11 |
12 |
13 |
14 | void doTask(const string& msg) {
15 | cout << msg << endl;
16 | }
17 |
18 |
19 |
20 | int main() {
21 | auto thFoo = std::thread(&doTask, "foo");
22 | auto thBar = std::thread(&doTask, "bar");
23 |
24 | thFoo.join();
25 | thBar.join();
26 |
27 | return 0;
28 | }
29 |
--------------------------------------------------------------------------------
/csharp/demo/demo03d-pass-arg.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * PASSING ARGUMENTS
3 | * Version D: Passing arguments by capturing them
4 | */
5 | using System;
6 | using System.Threading;
7 |
8 |
9 |
10 | class Demo03D : IRunnable
11 | {
12 | public void run()
13 | {
14 | const int COUNT = 10;
15 |
16 | new Thread(() =>
17 | {
18 |
19 | for (int i = 1; i <= COUNT; ++i)
20 | Console.WriteLine("Foo " + i);
21 |
22 | }).Start();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/cpp/cpp-std/demo01b-hello-functor.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | HELLO WORLD VERSION MULTITHREADING
3 | Version B: Using functors
4 | */
5 |
6 |
7 | #include
8 | #include
9 | #include
10 | using namespace std;
11 |
12 |
13 |
14 | class Example {
15 | public:
16 | void operator()(string message) {
17 | cout << message << endl;
18 | }
19 | };
20 |
21 |
22 |
23 | int main() {
24 | Example example;
25 |
26 | std::thread th(example, "Good day");
27 |
28 | th.join();
29 | return 0;
30 | }
31 |
--------------------------------------------------------------------------------
/cpp/cpp-std/demo00.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | INTRODUCTION TO MULTITHREADING
3 | You should try running this app several times and see results.
4 | */
5 |
6 |
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | void doTask() {
14 | for (int i = 0; i < 300; ++i)
15 | cout << "B";
16 | }
17 |
18 |
19 |
20 | int main() {
21 | std::thread th(&doTask);
22 |
23 | for (int i = 0; i < 300; ++i)
24 | cout << "A";
25 |
26 | th.join();
27 |
28 | cout << endl;
29 | return 0;
30 | }
31 |
--------------------------------------------------------------------------------
/cpp/cpp-boost/demo01b-hello-functor.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | HELLO WORLD VERSION MULTITHREADING
3 | Version B: Using functors
4 | */
5 |
6 |
7 | #include
8 | #include
9 | #include
10 | using namespace std;
11 |
12 |
13 |
14 | class Example {
15 | public:
16 | void operator()(string message) {
17 | cout << message << endl;
18 | }
19 | };
20 |
21 |
22 |
23 | int main() {
24 | Example example;
25 |
26 | boost::thread th(example, "Good day");
27 |
28 | th.join();
29 | return 0;
30 | }
31 |
--------------------------------------------------------------------------------
/cpp/cpp-std/demo01b-hello-class01.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | HELLO WORLD VERSION MULTITHREADING
3 | Version B: Using class methods
4 | */
5 |
6 |
7 | #include
8 | #include
9 | #include
10 | using namespace std;
11 |
12 |
13 |
14 | class Example {
15 | public:
16 | void doTask(string message) {
17 | cout << message << endl;
18 | }
19 | };
20 |
21 |
22 |
23 | int main() {
24 | Example example;
25 |
26 | std::thread th(&Example::doTask, &example, "Good day");
27 |
28 | th.join();
29 | return 0;
30 | }
31 |
--------------------------------------------------------------------------------
/csharp/demo/demo04-sleep.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * SLEEP
3 | */
4 | using System;
5 | using System.Threading;
6 |
7 |
8 |
9 | class Demo04 : IRunnable
10 | {
11 | public void run()
12 | {
13 | var thFoo = new Thread(() =>
14 | {
15 | Console.WriteLine("foo is sleeping");
16 | Thread.Sleep(3000);
17 | Console.WriteLine("foo wakes up");
18 | });
19 |
20 | thFoo.Start();
21 | thFoo.Join();
22 |
23 | Console.WriteLine("Good bye");
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/cpp/cpp-boost/demo00.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | INTRODUCTION TO MULTITHREADING
3 | You should try running this app several times and see results.
4 | */
5 |
6 |
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | void doTask() {
14 | for (int i = 0; i < 300; ++i)
15 | cout << "B";
16 | }
17 |
18 |
19 |
20 | int main() {
21 | boost::thread th(&doTask);
22 |
23 | for (int i = 0; i < 300; ++i)
24 | cout << "A";
25 |
26 | th.join();
27 |
28 | cout << endl;
29 | return 0;
30 | }
31 |
--------------------------------------------------------------------------------
/csharp/demo/demo06b-list-threads.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * LIST OF MULTIPLE THREADS
3 | * Version B: Using Linq
4 | */
5 | using System;
6 | using System.Linq;
7 | using System.Threading;
8 |
9 |
10 |
11 | class Demo06B : IRunnable
12 | {
13 | public void run()
14 | {
15 | var lstTh = Enumerable.Range(0, 5).Select(index => new Thread(() =>
16 | {
17 | Thread.Sleep(500);
18 | Console.WriteLine(index);
19 | })).ToList();
20 |
21 | lstTh.ForEach(th => th.Start());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/python/demo21a01_condition_variable.py:
--------------------------------------------------------------------------------
1 | '''
2 | CONDITION VARIABLES
3 | '''
4 |
5 | import time
6 | import threading
7 |
8 |
9 |
10 | condition_var = threading.Condition()
11 |
12 |
13 |
14 | def foo():
15 | print('foo is waiting...')
16 | with condition_var:
17 | condition_var.wait()
18 | print('foo resumed')
19 |
20 |
21 |
22 | def bar():
23 | time.sleep(3)
24 | with condition_var:
25 | condition_var.notify()
26 |
27 |
28 |
29 | threading.Thread(target=foo).start()
30 | threading.Thread(target=bar).start()
31 |
--------------------------------------------------------------------------------
/python/demo08a_return_value.py:
--------------------------------------------------------------------------------
1 | '''
2 | GETTING RETURNED VALUES FROM THREADS
3 | '''
4 |
5 | import threading
6 |
7 |
8 |
9 | def double_value(value):
10 | return value * 2
11 |
12 |
13 |
14 | res = {}
15 |
16 | th_foo = threading.Thread( target=lambda: res.update({ 'foo': double_value(5) }) )
17 | th_bar = threading.Thread( target=lambda: res.update({ 'bar': double_value(80) }) )
18 |
19 | th_foo.start()
20 | th_bar.start()
21 |
22 | # Wait until th_foo and th_far finish
23 | th_foo.join()
24 | th_bar.join()
25 |
26 | print(res['foo'])
27 | print(res['bar'])
28 |
--------------------------------------------------------------------------------
/java/src/demo01_hello/AppC02.java:
--------------------------------------------------------------------------------
1 | /*
2 | * HELLO WORLD VERSION MULTITHREADING
3 | * Version C02: Using function references
4 | */
5 |
6 | package demo01_hello;
7 |
8 |
9 |
10 | public class AppC02 {
11 |
12 | public static void main(String[] args) throws InterruptedException {
13 | var th = new Thread(AppC02::doTask);
14 |
15 | th.start();
16 |
17 | System.out.println("Hello from main thread");
18 | }
19 |
20 |
21 | private static void doTask() {
22 | System.out.println("Hello from example thread");
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/python/demo08b_return_value.py:
--------------------------------------------------------------------------------
1 | '''
2 | GETTING RETURNED VALUES FROM THREADS
3 | '''
4 |
5 | import threading
6 |
7 |
8 |
9 | def double_value(result: dict, name: str, value):
10 | result[name] = value * 2
11 |
12 |
13 |
14 | res = {}
15 |
16 | th_foo = threading.Thread( target=double_value, args=(res, 'foo', 5) )
17 | th_bar = threading.Thread( target=double_value, args=(res, 'bar', 80) )
18 |
19 | th_foo.start()
20 | th_bar.start()
21 |
22 | # Wait until th_foo and th_far finish
23 | th_foo.join()
24 | th_bar.join()
25 |
26 | print(res['foo'])
27 | print(res['bar'])
28 |
--------------------------------------------------------------------------------
/js-nodejs/demo12b01-data-race-single.js:
--------------------------------------------------------------------------------
1 | /*
2 | DATA RACES
3 | Version 01: Without multithreading
4 | */
5 |
6 | const getResult = N => {
7 | const a = new Int8Array(N + 1).fill(0);
8 | for (let i = 1; i <= N; ++i) {
9 | if (i % 2 === 0 || i % 3 === 0)
10 | a[i] = 1;
11 | }
12 | const result = a.reduce((x, y) => x + y, 0);
13 | return result;
14 | };
15 |
16 |
17 | const mainFunc = () => {
18 | const N = 1024;
19 | const result = getResult(N);
20 | console.log('Number of integers that are divisible by 2 or 3 is:', result);
21 | };
22 |
23 |
24 | mainFunc();
25 |
--------------------------------------------------------------------------------
/java/src/demo01_hello/AppC01.java:
--------------------------------------------------------------------------------
1 | /*
2 | * HELLO WORLD VERSION MULTITHREADING
3 | * Version C01: Using functions (via delegation from lambdas)
4 | */
5 |
6 | package demo01_hello;
7 |
8 |
9 |
10 | public class AppC01 {
11 |
12 | public static void main(String[] args) throws InterruptedException {
13 | var th = new Thread(() -> doTask());
14 |
15 | th.start();
16 |
17 | System.out.println("Hello from main thread");
18 | }
19 |
20 |
21 | private static void doTask() {
22 | System.out.println("Hello from example thread");
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/java/src/demo03_pass_arg/AppC.java:
--------------------------------------------------------------------------------
1 | /*
2 | * PASSING ARGUMENTS
3 | * Version C: Passing arguments by capturing them
4 | *
5 | * Note: The captured variables must be final or effectively final.
6 | */
7 |
8 | package demo03_pass_arg;
9 |
10 |
11 |
12 | public class AppC {
13 |
14 | public static void main(String[] args) throws InterruptedException {
15 | final int COUNT = 10;
16 |
17 | new Thread(() -> {
18 |
19 | for (int i = 1; i <= COUNT; ++i)
20 | System.out.println("value: " + i);
21 |
22 | }).start();
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/python/demo17a_reentrant_lock.py:
--------------------------------------------------------------------------------
1 | '''
2 | REENTRANT LOCKS (RECURSIVE MUTEXES)
3 | Version A: Introduction to reentrant locks
4 | '''
5 |
6 | import threading
7 |
8 |
9 |
10 | lock = threading.Lock()
11 |
12 |
13 |
14 | def do_task():
15 | with lock:
16 | print('First time acquiring the resource')
17 | with lock:
18 | print('Second time acquiring the resource')
19 |
20 |
21 |
22 | th = threading.Thread(target=do_task)
23 | th.start()
24 |
25 | # The thread th shall meet deadlock.
26 | # So, you will never get output "Second time the acquiring resource".
27 |
--------------------------------------------------------------------------------
/cpp/cpp-boost/demo03b-pass-arg.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | PASSING ARGUMENTS
3 | Version B: Passing constant references
4 | */
5 |
6 |
7 | #include
8 | #include
9 | #include
10 | using namespace std;
11 |
12 |
13 |
14 | void doTask(const string& msg) {
15 | cout << msg << endl;
16 | }
17 |
18 | void doTask(const string& msg) {
19 | cout << msg << endl;
20 | }
21 |
22 |
23 |
24 | int main() {
25 | boost::thread thFoo(&doTask, "foo");
26 | boost::thread thBar(&doTask, "bar");
27 |
28 | thFoo.join();
29 | thBar.join();
30 |
31 | return 0;
32 | }
33 |
--------------------------------------------------------------------------------
/csharp/demo/demo02a-join.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * THREAD JOINS
3 | */
4 | using System;
5 | using System.Threading;
6 |
7 |
8 |
9 | class Demo02A : IRunnable
10 | {
11 | public void run()
12 | {
13 | Thread th = new Thread(doHeavyTask);
14 |
15 | th.Start();
16 | th.Join();
17 |
18 | Console.WriteLine("Good bye!");
19 | }
20 |
21 | private void doHeavyTask() {
22 | // Do a heavy task, which takes a little time
23 | for (int i = 0; i < 2000000000; ++i);
24 |
25 | Console.WriteLine("Done!");
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/python/demo23a_thread_local.py:
--------------------------------------------------------------------------------
1 | '''
2 | THREAD-LOCAL STORAGE
3 | '''
4 |
5 | import time
6 | import threading
7 |
8 |
9 |
10 | data = threading.local()
11 |
12 |
13 |
14 | def print_local_value():
15 | print(data.value)
16 |
17 |
18 |
19 | def do_task_apple():
20 | data.value = 'APPLE'
21 | time.sleep(2)
22 | print_local_value()
23 |
24 |
25 |
26 | def do_task_banana():
27 | data.value = 'BANANA'
28 | time.sleep(2)
29 | print_local_value()
30 |
31 |
32 |
33 | threading.Thread(target=do_task_apple).start()
34 | threading.Thread(target=do_task_banana).start()
35 |
--------------------------------------------------------------------------------
/python/demo12c01_race_cond_data_race.py:
--------------------------------------------------------------------------------
1 | '''
2 | RACE CONDITIONS AND DATA RACES
3 | '''
4 |
5 | import time
6 | import threading
7 |
8 |
9 |
10 | counter = 0
11 |
12 |
13 |
14 | def do_task():
15 | global counter
16 |
17 | for _ in range(1000):
18 | temp = counter + 1
19 | time.sleep(0.0001)
20 | counter = temp
21 |
22 |
23 |
24 | lstth = [threading.Thread(target=do_task) for _ in range(32)]
25 |
26 | for th in lstth:
27 | th.start()
28 |
29 | for th in lstth:
30 | th.join()
31 |
32 | print('counter =', counter)
33 | # We are NOT sure that counter = 32000
34 |
--------------------------------------------------------------------------------
/python/demo15a_deadlock.py:
--------------------------------------------------------------------------------
1 | '''
2 | DEADLOCK
3 | Version A
4 | '''
5 |
6 | import threading
7 |
8 |
9 |
10 | mutex = threading.Lock()
11 |
12 |
13 |
14 | def do_task(name: str):
15 | mutex.acquire()
16 | print(f'{name} acquired resource')
17 | # mutex.release() # Forget this statement ==> deadlock
18 |
19 |
20 |
21 | th_foo = threading.Thread(target=do_task, args=('foo',))
22 | th_bar = threading.Thread(target=do_task, args=('bar',))
23 |
24 | th_foo.start()
25 | th_bar.start()
26 | th_foo.join()
27 | th_bar.join()
28 |
29 | print('You will never see this statement due to deadlock!')
30 |
--------------------------------------------------------------------------------
/python/demo17c_reentrant_lock.py:
--------------------------------------------------------------------------------
1 | '''
2 | REENTRANT LOCKS (RECURSIVE MUTEXES)
3 | Version C: A multithreaded app example
4 | '''
5 |
6 | import time
7 | import threading
8 |
9 |
10 |
11 | lock = threading.RLock()
12 |
13 |
14 |
15 | def do_task(name: str):
16 | time.sleep(1)
17 | with lock:
18 | print(f'First time {name} acquiring the resource')
19 | with lock:
20 | print(f'Second time {name} acquiring the resource')
21 |
22 |
23 |
24 | NUM_THREADS = 3
25 |
26 | for i in range(NUM_THREADS):
27 | threading.Thread(target=do_task, args=(chr(i + 65),)).start()
28 |
--------------------------------------------------------------------------------
/csharp/demo/demo03a-pass-arg.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * PASSING ARGUMENTS
3 | * Version A: Using lambdas
4 | */
5 | using System;
6 | using System.Threading;
7 |
8 |
9 |
10 | class Demo03C : IRunnable
11 | {
12 | public void run()
13 | {
14 | Thread thFoo = new Thread(() => doTask(1, 2, "red"));
15 | Thread thBar = new Thread(() => doTask(3, 4, "blue"));
16 |
17 | thFoo.Start();
18 | thBar.Start();
19 | }
20 |
21 |
22 | private void doTask(int a, double b, string c)
23 | {
24 | Console.WriteLine($"{a} {b} {c}");
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/python/demo11b_exec_service.py:
--------------------------------------------------------------------------------
1 | '''
2 | EXECUTOR SERVICES AND THREAD POOLS
3 | Version B: The executor service containing multiple threads
4 | '''
5 |
6 | import time
7 | from concurrent.futures import ThreadPoolExecutor
8 |
9 |
10 |
11 | def do_task(name: str):
12 | print(f'Task {name} is starting')
13 | time.sleep(3)
14 | print(f'Task {name} is completed')
15 |
16 |
17 |
18 | NUM_TASKS = 5
19 | executor = ThreadPoolExecutor(max_workers=2)
20 |
21 | for i in range(NUM_TASKS):
22 | task_name = chr(i + 65)
23 | executor.submit(do_task, task_name)
24 |
25 | executor.shutdown(wait=True)
26 |
--------------------------------------------------------------------------------
/cpp/cpp-std/demo04a-sleep.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | SLEEP
3 | Version A: Sleep for a specific duration
4 | */
5 |
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | using namespace std;
12 |
13 |
14 |
15 | void doTask(string name) {
16 | cout << name << " is sleeping" << endl;
17 | std::this_thread::sleep_for(std::chrono::seconds(3));
18 | cout << name << " wakes up" << endl;
19 | }
20 |
21 |
22 |
23 | int main() {
24 | auto thFoo = std::thread(&doTask, "foo");
25 |
26 | thFoo.join();
27 |
28 | cout << "Good bye" << endl;
29 | return 0;
30 | }
31 |
--------------------------------------------------------------------------------
/java/src/demo06_list_threads/AppB02.java:
--------------------------------------------------------------------------------
1 | /*
2 | * LIST OF MULTIPLE THREADS
3 | * Version B02: Using streams (shorten code, no variable to store list of threads)
4 | */
5 |
6 | package demo06_list_threads;
7 |
8 | import java.util.stream.IntStream;
9 |
10 |
11 |
12 | public class AppB02 {
13 |
14 | public static void main(String[] args) {
15 | IntStream.range(0, 5).forEach(i -> new Thread(() -> {
16 |
17 | try { Thread.sleep(500); }
18 | catch (InterruptedException e) { }
19 |
20 | System.out.print(i);
21 |
22 | }).start());
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/cpp/cpp-std/demo01b-hello-class02.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | HELLO WORLD VERSION MULTITHREADING
3 | Version B: Using class methods
4 | */
5 |
6 |
7 | #include
8 | #include
9 | #include
10 | using namespace std;
11 |
12 |
13 |
14 | class Example {
15 | public:
16 | void run() {
17 | std::thread th(&Example::doTask, this, "Good day");
18 | th.join();
19 | }
20 |
21 | private:
22 | void doTask(string message) {
23 | cout << message << endl;
24 | }
25 | };
26 |
27 |
28 |
29 | int main() {
30 | Example example;
31 | example.run();
32 | return 0;
33 | }
34 |
--------------------------------------------------------------------------------
/cpp/cpp-std/demo01b-hello-class03.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | HELLO WORLD VERSION MULTITHREADING
3 | Version B: Using class methods
4 | */
5 |
6 |
7 | #include
8 | #include
9 | #include
10 | using namespace std;
11 |
12 |
13 |
14 | class Example {
15 | public:
16 | void run() {
17 | std::thread th(&Example::doTask, "Good day");
18 | th.join();
19 | }
20 |
21 | private:
22 | static void doTask(string message) {
23 | cout << message << endl;
24 | }
25 | };
26 |
27 |
28 |
29 | int main() {
30 | Example example;
31 | example.run();
32 | return 0;
33 | }
34 |
--------------------------------------------------------------------------------
/csharp/demo/demo00-intro.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * INTRODUCTION TO MULTITHREADING
3 | * You should try running this app several times and see results.
4 | */
5 | using System;
6 | using System.Threading;
7 |
8 |
9 |
10 | class Demo00 : IRunnable
11 | {
12 | public void run()
13 | {
14 | Thread th = new Thread(doTask);
15 |
16 | th.Start();
17 |
18 | for (int i = 0; i < 300; ++i)
19 | Console.Write("A");
20 | }
21 |
22 | private void doTask()
23 | {
24 | for (int i = 0; i < 300; ++i)
25 | Console.Write("B");
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/java/src/demo01_hello/AppA02.java:
--------------------------------------------------------------------------------
1 | /*
2 | * HELLO WORLD VERSION MULTITHREADING
3 | * Version A02: Using class Thread (anonymous subclass)
4 | */
5 |
6 | package demo01_hello;
7 |
8 |
9 |
10 | public class AppA02 {
11 |
12 | public static void main(String[] args) throws InterruptedException {
13 | var th = new Thread() {
14 | @Override
15 | public void run() {
16 | System.out.println("Hello from example thread");
17 | }
18 | };
19 |
20 | th.start();
21 |
22 | System.out.println("Hello from main thread");
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/java/src/demo01_hello/AppB02.java:
--------------------------------------------------------------------------------
1 | /*
2 | * HELLO WORLD VERSION MULTITHREADING
3 | * Version B02: Using inteface Runnable with lambdas
4 | */
5 |
6 | package demo01_hello;
7 |
8 |
9 |
10 | public class AppB02 {
11 |
12 | public static void main(String[] args) throws InterruptedException {
13 | Runnable doTask = () -> System.out.println("Hello from example thread");
14 |
15 | var th1 = new Thread(doTask);
16 | var th2 = new Thread(doTask);
17 |
18 | th1.start();
19 | th2.start();
20 |
21 | System.out.println("Hello from main thread");
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/python/demo21a02_condition_variable.py:
--------------------------------------------------------------------------------
1 | '''
2 | CONDITION VARIABLES
3 | '''
4 |
5 | import time
6 | import threading
7 |
8 |
9 |
10 | condition_var = threading.Condition()
11 |
12 |
13 |
14 | def foo():
15 | print('foo is waiting...')
16 | with condition_var:
17 | condition_var.wait()
18 | print('foo resumed')
19 |
20 |
21 |
22 | def bar():
23 | for _ in range(3):
24 | time.sleep(2)
25 | with condition_var:
26 | condition_var.notify()
27 |
28 |
29 |
30 | _ = [ threading.Thread(target=foo).start() for _ in range(3) ]
31 | threading.Thread(target=bar).start()
32 |
--------------------------------------------------------------------------------
/csharp/demo/demo01a-hello.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * HELLO WORLD VERSION MULTITHREADING
3 | * Version A: Using functions
4 | */
5 | using System;
6 | using System.Threading;
7 |
8 |
9 |
10 | class Demo01A : IRunnable
11 | {
12 | public void run()
13 | {
14 | Thread th = new Thread(doTask);
15 | // or
16 | // Thread th = new Thread(new ThreadStart(doTask));
17 |
18 | th.Start();
19 | Console.WriteLine("Hello from main thread");
20 | }
21 |
22 | private void doTask()
23 | {
24 | Console.WriteLine("Hello from example thread");
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/python/demo21a03_condition_variable.py:
--------------------------------------------------------------------------------
1 | '''
2 | CONDITION VARIABLES
3 | '''
4 |
5 | import time
6 | import threading
7 |
8 |
9 |
10 | condition_var = threading.Condition()
11 |
12 |
13 |
14 | def foo():
15 | print('foo is waiting...')
16 | with condition_var:
17 | condition_var.wait()
18 | print('foo resumed')
19 |
20 |
21 |
22 | def bar():
23 | time.sleep(3)
24 | with condition_var:
25 | # Notify all waiting threads
26 | condition_var.notify_all()
27 |
28 |
29 |
30 | _ = [ threading.Thread(target=foo).start() for _ in range(3) ]
31 | threading.Thread(target=bar).start()
32 |
--------------------------------------------------------------------------------
/java/src/demo01_hello/AppA01.java:
--------------------------------------------------------------------------------
1 | /*
2 | * HELLO WORLD VERSION MULTITHREADING
3 | * Version A01: Using class Thread (original way)
4 | */
5 |
6 | package demo01_hello;
7 |
8 |
9 |
10 | public class AppA01 {
11 |
12 | public static void main(String[] args) throws InterruptedException {
13 | var th = new ExampleThread();
14 | th.start();
15 | System.out.println("Hello from main thread");
16 | }
17 |
18 | }
19 |
20 |
21 |
22 | class ExampleThread extends Thread {
23 | @Override
24 | public void run() {
25 | System.out.println("Hello from example thread");
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/python/demo12c02_race_cond_data_race.py:
--------------------------------------------------------------------------------
1 | '''
2 | RACE CONDITIONS AND DATA RACES
3 | '''
4 |
5 | import time
6 | import threading
7 |
8 |
9 |
10 | counter = 0
11 |
12 |
13 |
14 | def do_task_a():
15 | global counter
16 | time.sleep(1)
17 |
18 | while counter < 10:
19 | counter += 1
20 |
21 | print('A won !!!')
22 |
23 |
24 |
25 | def do_task_b():
26 | global counter
27 | time.sleep(1)
28 |
29 | while counter > -10:
30 | counter -= 1
31 |
32 | print('B won !!!')
33 |
34 |
35 |
36 | threading.Thread(target=do_task_a).start()
37 | threading.Thread(target=do_task_b).start()
38 |
--------------------------------------------------------------------------------
/cpp/cpp-boost/demo01b-hello-class03.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | HELLO WORLD VERSION MULTITHREADING
3 | Version B: Using class methods
4 | */
5 |
6 |
7 | #include
8 | #include
9 | #include
10 | using namespace std;
11 |
12 |
13 |
14 | class Example {
15 | public:
16 | void run() {
17 | boost::thread th(&Example::doTask, "Good day");
18 | th.join();
19 | }
20 |
21 | private:
22 | static void doTask(string message) {
23 | cout << message << endl;
24 | }
25 | };
26 |
27 |
28 |
29 | int main() {
30 | Example example;
31 | example.run();
32 | return 0;
33 | }
34 |
--------------------------------------------------------------------------------
/cpp/cpp-boost/demo04a-sleep.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | SLEEP
3 | Version A: Sleep for a specific duration
4 | */
5 |
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | using namespace std;
12 |
13 |
14 |
15 | void doTask(string name) {
16 | cout << name << " is sleeping" << endl;
17 | boost::this_thread::sleep_for(boost::chrono::seconds(3));
18 | cout << name << " wakes up" << endl;
19 | }
20 |
21 |
22 |
23 | int main() {
24 | boost::thread thFoo(&doTask, "foo");
25 |
26 | thFoo.join();
27 |
28 | cout << "Good bye" << endl;
29 | return 0;
30 | }
31 |
--------------------------------------------------------------------------------
/cpp/cpp-std/demo06a-list-threads.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | LIST OF MULTIPLE THREADS
3 | Version A: Using standard arrays
4 | */
5 |
6 |
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | void doTask(int index) {
14 | cout << index;
15 | }
16 |
17 |
18 |
19 | int main() {
20 | constexpr int NUM_THREADS = 5;
21 |
22 | std::thread lstTh[NUM_THREADS];
23 |
24 | for (int i = 0; i < NUM_THREADS; ++i) {
25 | lstTh[i] = std::thread(&doTask, i);
26 | }
27 |
28 | for (auto&& th : lstTh) {
29 | th.join();
30 | }
31 |
32 | cout << endl;
33 | return 0;
34 | }
35 |
--------------------------------------------------------------------------------
/java/src/demo03_pass_arg/AppB.java:
--------------------------------------------------------------------------------
1 | /*
2 | * PASSING ARGUMENTS
3 | * Version B: Passing arguments to functions
4 | */
5 |
6 | package demo03_pass_arg;
7 |
8 |
9 |
10 | public class AppB {
11 |
12 | public static void main(String[] args) throws InterruptedException {
13 | var thFoo = new Thread(() -> doTask(1, 2, "red"));
14 | var thBar = new Thread(() -> doTask(3, 4, "blue"));
15 |
16 | thFoo.start();
17 | thBar.start();
18 | }
19 |
20 |
21 | private static void doTask(int a, double b, String c) {
22 | System.out.printf("%d %.1f %s %n", a, b, c);
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/cpp/cpp-std/demo05-id.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | GETTING THREAD'S ID
3 | */
4 |
5 |
6 | #include
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | void doTask() {
14 | std::this_thread::sleep_for(std::chrono::seconds(2));
15 | cout << std::this_thread::get_id() << endl;
16 | }
17 |
18 |
19 |
20 | int main() {
21 | auto thFoo = std::thread(&doTask);
22 | auto thBar = std::thread(&doTask);
23 |
24 | cout << "foo's id: " << thFoo.get_id() << endl;
25 | cout << "bar's id: " << thBar.get_id() << endl;
26 |
27 | thFoo.join();
28 | thBar.join();
29 |
30 | return 0;
31 | }
32 |
--------------------------------------------------------------------------------
/python/exer04_dining_philosophers.py:
--------------------------------------------------------------------------------
1 | '''
2 | THE DINING PHILOSOPHERS PROBLEM
3 | '''
4 |
5 | import time
6 | import threading
7 |
8 |
9 |
10 | def do_task_philosopher(chstk: list, n_philo: int, id_philo: int):
11 | time.sleep(1)
12 |
13 | with chstk[id_philo]:
14 | with chstk[(id_philo + 1) % n_philo]:
15 | print(f'Philosopher #{id_philo} is eating the rice')
16 |
17 |
18 |
19 | NUM_PHILOSOPHERS = 5
20 | chopstick = [threading.Lock() for _ in range(NUM_PHILOSOPHERS)]
21 |
22 | for i in range(NUM_PHILOSOPHERS):
23 | threading.Thread(target=do_task_philosopher, args=(chopstick, NUM_PHILOSOPHERS, i)).start()
24 |
--------------------------------------------------------------------------------
/cpp/cpp-boost/demo01b-hello-class01.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | HELLO WORLD VERSION MULTITHREADING
3 | Version B: Using class methods
4 | */
5 |
6 |
7 | #include
8 | #include
9 | #include
10 | using namespace std;
11 |
12 |
13 |
14 | class Example {
15 | public:
16 | void doTask(string message) {
17 | cout << message << endl;
18 | }
19 | };
20 |
21 |
22 |
23 | int main() {
24 | Example example;
25 |
26 | boost::thread th(&Example::doTask, &example, "Good day");
27 | // boost::thread th(boost::bind(&Example::doTask, &example, "Good day"));
28 |
29 | th.join();
30 | return 0;
31 | }
32 |
--------------------------------------------------------------------------------
/java/src/demo05_id/App.java:
--------------------------------------------------------------------------------
1 | /*
2 | * GETTING THREAD'S ID
3 | */
4 |
5 | package demo05_id;
6 |
7 |
8 |
9 | public class App {
10 |
11 | public static void main(String[] args) {
12 | Runnable doTask = () -> {
13 | long id = Thread.currentThread().getId();
14 | System.out.println(id);
15 | };
16 |
17 | var thFoo = new Thread(doTask);
18 | var thBar = new Thread(doTask);
19 |
20 | System.out.println("foo's id: " + thFoo.getId());
21 | System.out.println("bar's id: " + thBar.getId());
22 |
23 | thFoo.start();
24 | thBar.start();
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/cpp/cpp-boost/demo12a-race-condition.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | RACE CONDITIONS
3 | */
4 |
5 |
6 | #include
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | void doTask(int index) {
14 | boost::this_thread::sleep_for(boost::chrono::seconds(1));
15 | cout << index;
16 | }
17 |
18 |
19 |
20 | int main() {
21 | const int NUM_THREADS = 4;
22 | boost::thread_group lstTh;
23 |
24 | for (int i = 0; i < NUM_THREADS; ++i) {
25 | lstTh.add_thread(new boost::thread(&doTask, i));
26 | }
27 |
28 | lstTh.join_all();
29 |
30 | cout << endl;
31 | return 0;
32 | }
33 |
--------------------------------------------------------------------------------
/cpp/cpp-std/demo24-volatile.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | THE VOLATILE KEYWORD
3 | */
4 |
5 |
6 | #include
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | volatile bool isRunning;
14 |
15 |
16 |
17 | void doTask() {
18 | while (isRunning) {
19 | cout << "Running..." << endl;
20 | std::this_thread::sleep_for(std::chrono::seconds(2));
21 | }
22 | }
23 |
24 |
25 |
26 | int main() {
27 | isRunning = true;
28 | auto th = std::thread(&doTask);
29 |
30 | std::this_thread::sleep_for(std::chrono::seconds(6));
31 | isRunning = false;
32 |
33 | th.join();
34 | return 0;
35 | }
36 |
--------------------------------------------------------------------------------
/cpp/cpp-boost/demo05-id.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | GETTING THREAD'S ID
3 | */
4 |
5 |
6 | #include
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | void doTask() {
14 | boost::this_thread::sleep_for(boost::chrono::seconds(2));
15 | cout << boost::this_thread::get_id() << endl;
16 | }
17 |
18 |
19 |
20 | int main() {
21 | boost::thread thFoo(&doTask);
22 | boost::thread thBar(&doTask);
23 |
24 | cout << "foo's id: " << thFoo.get_id() << endl;
25 | cout << "bar's id: " << thBar.get_id() << endl;
26 |
27 | thFoo.join();
28 | thBar.join();
29 |
30 | return 0;
31 | }
32 |
--------------------------------------------------------------------------------
/cpp/cpp-boost/demo06a-list-threads.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | LIST OF MULTIPLE THREADS
3 | Version A: Using standard arrays
4 | */
5 |
6 |
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | void doTask(int index) {
14 | cout << index;
15 | }
16 |
17 |
18 |
19 | int main() {
20 | const int NUM_THREADS = 5;
21 |
22 | boost::thread lstTh[NUM_THREADS];
23 |
24 | for (int i = 0; i < NUM_THREADS; ++i) {
25 | lstTh[i] = boost::thread(&doTask, i);
26 | }
27 |
28 | for (int i = 0; i < NUM_THREADS; ++i) {
29 | lstTh[i].join();
30 | }
31 |
32 | cout << endl;
33 | return 0;
34 | }
35 |
--------------------------------------------------------------------------------
/java/src/demo00_intro/App.java:
--------------------------------------------------------------------------------
1 | /*
2 | * INTRODUCTION TO MULTITHREADING
3 | * You should try running this app several times and see results.
4 | */
5 |
6 | package demo00_intro;
7 |
8 |
9 |
10 | public class App {
11 |
12 | public static void main(String[] args) {
13 | Thread th = new ExampleThread();
14 |
15 | th.start();
16 |
17 | for (int i = 0; i < 300; ++i)
18 | System.out.print("A");
19 | }
20 |
21 | }
22 |
23 |
24 |
25 | class ExampleThread extends Thread {
26 | @Override
27 | public void run() {
28 | for (int i = 0; i < 300; ++i)
29 | System.out.print("B");
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/cpp/cpp-pthread/demo04-sleep.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | SLEEP
3 | */
4 |
5 |
6 | #include
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | void* doTask(void* arg) {
14 | auto name = (const char*) arg;
15 |
16 | cout << name << " is sleeping" << endl;
17 | sleep(2);
18 | cout << name << " wakes up" << endl;
19 |
20 | pthread_exit(nullptr);
21 | return nullptr;
22 | }
23 |
24 |
25 |
26 | int main() {
27 | pthread_t tid;
28 | int ret = 0;
29 |
30 | ret = pthread_create(&tid, nullptr, &doTask, (void*)"foo");
31 |
32 | ret = pthread_join(tid, nullptr);
33 |
34 | return 0;
35 | }
36 |
--------------------------------------------------------------------------------
/java/src/demo04_sleep/App.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SLEEP
3 | */
4 |
5 | package demo04_sleep;
6 |
7 |
8 |
9 | public class App {
10 |
11 | public static void main(String[] args) throws InterruptedException {
12 | var thFoo = new Thread(() -> {
13 | System.out.println("foo is sleeping");
14 |
15 | try {
16 | Thread.sleep(3000);
17 | } catch (InterruptedException e) {
18 |
19 | }
20 |
21 | System.out.println("foo wakes up");
22 | });
23 |
24 |
25 | thFoo.start();
26 | thFoo.join();
27 |
28 |
29 | System.out.println("Good bye");
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/cpp/cpp-pthread/demo02-join.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | THREAD JOINS
3 | */
4 |
5 |
6 | #include
7 | #include
8 | using namespace std;
9 |
10 |
11 |
12 | void* doHeavyTask(void*) {
13 | // Do a heavy task, which takes a little time
14 | for (int i = 0; i < 2000000000; ++i);
15 |
16 | cout << "Done!" << endl;
17 |
18 | pthread_exit(nullptr);
19 | return nullptr;
20 | }
21 |
22 |
23 |
24 | int main() {
25 | pthread_t tid;
26 | int ret = 0;
27 |
28 | ret = pthread_create(&tid, nullptr, &doHeavyTask, nullptr);
29 |
30 | ret = pthread_join(tid, nullptr);
31 |
32 | cout << "Good bye!" << endl;
33 |
34 | return 0;
35 | }
36 |
--------------------------------------------------------------------------------
/java/src/demo12_race_condition/AppA.java:
--------------------------------------------------------------------------------
1 | /*
2 | * RACE CONDITIONS
3 | */
4 |
5 | package demo12_race_condition;
6 |
7 | import java.util.stream.IntStream;
8 |
9 |
10 |
11 | public class AppA {
12 |
13 | public static void main(String[] args) {
14 | final int NUM_THREADS = 4;
15 |
16 |
17 | var lstTh = IntStream.range(0, NUM_THREADS)
18 | .mapToObj(i -> new Thread(() -> {
19 | try { Thread.sleep(1000); } catch (InterruptedException e) { }
20 | System.out.print(i);
21 | }))
22 | .toList();
23 |
24 |
25 | lstTh.forEach(Thread::start);
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/cpp/cpp-boost/demo24-volatile.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | THE VOLATILE KEYWORD
3 | */
4 |
5 |
6 | #include
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | volatile bool isRunning;
14 |
15 |
16 |
17 | void doTask() {
18 | while (isRunning) {
19 | cout << "Running..." << endl;
20 | boost::this_thread::sleep_for(boost::chrono::seconds(2));
21 | }
22 | }
23 |
24 |
25 |
26 | int main() {
27 | isRunning = true;
28 | boost::thread th(&doTask);
29 |
30 | boost::this_thread::sleep_for(boost::chrono::seconds(6));
31 | isRunning = false;
32 |
33 | th.join();
34 | return 0;
35 | }
36 |
--------------------------------------------------------------------------------
/csharp/demo/demo01b01-hello.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * HELLO WORLD VERSION MULTITHREADING
3 | * Version B01: Using lambdas with ThreadStart
4 | */
5 | using System;
6 | using System.Threading;
7 |
8 |
9 |
10 | class Demo01B01 : IRunnable
11 | {
12 | public void run()
13 | {
14 | ThreadStart doTask = new ThreadStart(() =>
15 | {
16 | Console.WriteLine("Hello from example thread");
17 | });
18 |
19 | Thread th1 = new Thread(doTask);
20 | Thread th2 = new Thread(doTask);
21 |
22 | th1.Start();
23 | th2.Start();
24 |
25 | Console.WriteLine("Hello from main thread");
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/python/demo14_synchronized_block.py:
--------------------------------------------------------------------------------
1 | '''
2 | SYNCHRONIZED BLOCKS
3 | '''
4 |
5 | import time
6 | import threading
7 |
8 |
9 |
10 | mutex = threading.Lock()
11 | counter = 0
12 |
13 |
14 |
15 | def do_task():
16 | global counter
17 |
18 | with mutex:
19 | for _ in range(1000):
20 | temp = counter + 1
21 | time.sleep(0.0001)
22 | counter = temp
23 |
24 |
25 |
26 | NUM_THREADS = 32
27 | lstth = [threading.Thread(target=do_task) for _ in range(NUM_THREADS)]
28 |
29 | for th in lstth:
30 | th.start()
31 |
32 | for th in lstth:
33 | th.join()
34 |
35 | print('counter =', counter)
36 | # We are sure that counter = 32000
37 |
--------------------------------------------------------------------------------
/cpp/cpp-std/demo23a01-thread-local.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | THREAD-LOCAL STORAGE
3 | Introduction
4 | The basic way to use thread-local storage
5 | */
6 |
7 |
8 | #include
9 | #include
10 | #include
11 | using namespace std;
12 |
13 |
14 |
15 | thread_local string value = "NOT SET";
16 |
17 |
18 |
19 | void doTask() {
20 | cout << value << endl;
21 | }
22 |
23 |
24 |
25 | int main() {
26 | // Main thread sets value = "APPLE"
27 | value = "APPLE";
28 | cout << value << endl;
29 |
30 | // Child thread gets value
31 | // Expected output: "NOT SET"
32 | auto th = std::thread(&doTask);
33 | th.join();
34 |
35 | return 0;
36 | }
37 |
--------------------------------------------------------------------------------
/java/src/demo02_join/AppB.java:
--------------------------------------------------------------------------------
1 | /*
2 | * THREAD JOINS
3 | */
4 |
5 | package demo02_join;
6 |
7 |
8 |
9 | public class AppB {
10 |
11 | public static void main(String[] args) {
12 | Thread thFoo = new Thread(() -> System.out.println("foo"));
13 | Thread thBar = new Thread(() -> System.out.println("bar"));
14 |
15 | thFoo.start();
16 | thBar.start();
17 |
18 | // thFoo.join();
19 | // thBar.join();
20 |
21 | /*
22 | * We do not need to call thFoo.join() and thBar.join().
23 | * The reason is main thread will wait for the completion of all threads before app exits.
24 | */
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/cpp/cpp-std/demo07-terminate.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | FORCING A THREAD TO TERMINATE (i.e. killing the thread)
3 | */
4 |
5 |
6 | #include
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | volatile bool isRunning;
14 |
15 |
16 |
17 | void doTask() {
18 | while (isRunning) {
19 | cout << "Running..." << endl;
20 | std::this_thread::sleep_for(std::chrono::seconds(2));
21 | }
22 | }
23 |
24 |
25 |
26 | int main() {
27 | isRunning = true;
28 | auto th = std::thread(&doTask);
29 |
30 | std::this_thread::sleep_for(std::chrono::seconds(6));
31 | isRunning = false;
32 |
33 | th.join();
34 | return 0;
35 | }
36 |
--------------------------------------------------------------------------------
/csharp/demoex/demoex-async-future-a03.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * ASYNCHRONOUS PROGRAMMING WITH THE FUTURE/TASK
3 | */
4 | using System;
5 | using System.Threading.Tasks;
6 | #pragma warning disable CS1998
7 |
8 |
9 |
10 | class DemoExAsyncA03 : IRunnable
11 | {
12 | public async void run()
13 | {
14 | var task = getSquared(7);
15 |
16 | // Waiting for task completion
17 | task.Wait();
18 |
19 | int result = await task;
20 | Console.WriteLine(result);
21 | }
22 |
23 | private async Task getSquared(int x)
24 | {
25 | return x * x;
26 | }
27 | }
28 |
29 |
30 |
31 | #pragma warning restore CS1998
32 |
--------------------------------------------------------------------------------
/python/demo05_id.py:
--------------------------------------------------------------------------------
1 | '''
2 | GETTING THREAD'S ID
3 | '''
4 |
5 | import time
6 | import threading
7 |
8 |
9 |
10 | def do_task():
11 | time.sleep(1)
12 | tid = threading.get_ident()
13 | tid_native = threading.get_native_id()
14 | print('id of current thread:', tid)
15 | print('native id of current thread from operating system:', tid_native)
16 |
17 |
18 |
19 | th_foo = threading.Thread(target=do_task)
20 | th_bar = threading.Thread(target=do_task)
21 |
22 | th_foo.start()
23 | th_bar.start()
24 |
25 | print("foo's id:", th_foo.ident)
26 | print("foo's native id:", th_foo.native_id)
27 | print("bar's id:", th_bar.ident)
28 | print("bar's native id:", th_bar.native_id)
29 |
--------------------------------------------------------------------------------
/csharp/demo/demo01ex-name.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * HELLO WORLD VERSION MULTITHREADING
3 | * Version extra: Getting thread's name
4 | */
5 | using System;
6 | using System.Threading;
7 |
8 |
9 |
10 | class Demo01ExtraName : IRunnable
11 | {
12 | public void run()
13 | {
14 | Thread thFoo = new Thread(doTask)
15 | {
16 | Name = "foo"
17 | };
18 |
19 | Thread thBar = new Thread(doTask);
20 | thBar.Name = "bar";
21 |
22 | thFoo.Start();
23 | thBar.Start();
24 | }
25 |
26 | private void doTask()
27 | {
28 | Console.WriteLine($"My name is {Thread.CurrentThread.Name}");
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/python/exer02a01_producer_consumer.py:
--------------------------------------------------------------------------------
1 | '''
2 | THE PRODUCER-CONSUMER PROBLEM
3 |
4 | SOLUTION TYPE A: USING BLOCKING QUEUES
5 | Version A01: 1 slow producer, 1 fast consumer
6 | '''
7 |
8 | import time
9 | from queue import Queue
10 | import threading
11 |
12 |
13 |
14 | def producer(q: Queue):
15 | i = 1
16 |
17 | while True:
18 | q.put(i)
19 | time.sleep(1)
20 | i += 1
21 |
22 |
23 |
24 | def consumer(q: Queue):
25 | while True:
26 | data = q.get()
27 | print('Consumer', data)
28 |
29 |
30 |
31 | blkq = Queue()
32 | threading.Thread(target=producer, args=(blkq,)).start()
33 | threading.Thread(target=consumer, args=(blkq,)).start()
34 |
--------------------------------------------------------------------------------
/python/demo18a01_barrier.py:
--------------------------------------------------------------------------------
1 | '''
2 | BARRIERS AND LATCHES
3 | Version A: Barriers
4 | '''
5 |
6 | import time
7 | import threading
8 |
9 |
10 |
11 | sync_point = threading.Barrier(parties=3)
12 |
13 |
14 |
15 | def process_request(user_name: str, wait_time: int):
16 | time.sleep(wait_time)
17 |
18 | print(f'Get request from {user_name}')
19 | sync_point.wait()
20 |
21 | print(f'Process request for {user_name}')
22 | sync_point.wait()
23 |
24 | print(f'Done {user_name}')
25 |
26 |
27 |
28 | lstarg = [
29 | ('lorem', 1),
30 | ('ipsum', 2),
31 | ('dolor', 3)
32 | ]
33 |
34 | _ = [ threading.Thread(target=process_request, args=arg).start() for arg in lstarg ]
35 |
--------------------------------------------------------------------------------
/cpp/cpp-pthread/demo01-hello.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | HELLO WORLD VERSION MULTITHREADING
3 | */
4 |
5 |
6 | #include
7 | #include
8 | using namespace std;
9 |
10 |
11 |
12 | void* doTask(void*) {
13 | cout << "Hello from example thread" << endl;
14 |
15 | pthread_exit(nullptr);
16 | return nullptr;
17 | }
18 |
19 |
20 |
21 | int main() {
22 | pthread_t tid;
23 | int ret = 0;
24 |
25 | ret = pthread_create(&tid, nullptr, &doTask, nullptr);
26 |
27 | /*
28 | if (ret) {
29 | cerr << "Error: Unable to create thread " << ret << endl;
30 | return 1;
31 | }
32 | */
33 |
34 | ret = pthread_join(tid, nullptr);
35 | return 0;
36 | }
37 |
--------------------------------------------------------------------------------
/java/src/demo02_join/AppA.java:
--------------------------------------------------------------------------------
1 | /*
2 | * THREAD JOINS
3 | */
4 |
5 | package demo02_join;
6 |
7 |
8 |
9 | public class AppA {
10 |
11 | public static void main(String[] args) throws InterruptedException {
12 | Thread th = new Thread(() -> doHeavyTask());
13 |
14 | th.start();
15 | th.join();
16 |
17 | System.out.println("Good bye!");
18 | }
19 |
20 |
21 | @SuppressWarnings("unused")
22 | private static void doHeavyTask() {
23 | // Do a heavy task, which takes a little time
24 | long sum = 0;
25 | for (int i = 0; i < 2000000000; ++i)
26 | sum += i;
27 |
28 | System.out.println("Done!");
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/cpp/cpp-boost/demo06c-list-threads.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | LIST OF MULTIPLE THREADS
3 | Version C: Using the boost::thread_group
4 | */
5 |
6 |
7 | #include
8 | #include
9 | #include
10 | using namespace std;
11 |
12 |
13 |
14 | void doTask(int index) {
15 | cout << index;
16 | }
17 |
18 |
19 |
20 | int main() {
21 | const int NUM_THREADS = 5;
22 |
23 | boost::thread_group lstTh;
24 |
25 | for (int i = 0; i < NUM_THREADS; ++i) {
26 | lstTh.add_thread(new boost::thread(&doTask, i));
27 | // lstTh.create_thread(boost::bind(&doTask, i));
28 | }
29 |
30 | lstTh.join_all();
31 |
32 | cout << endl;
33 | return 0;
34 | }
35 |
--------------------------------------------------------------------------------
/csharp/demo/demo02b-join.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * THREAD JOINS
3 | */
4 | using System;
5 | using System.Threading;
6 |
7 |
8 |
9 | class Demo02B : IRunnable
10 | {
11 | public void run()
12 | {
13 | Thread thFoo = new Thread(() => Console.WriteLine("foo"));
14 | Thread thBar = new Thread(() => Console.WriteLine("bar"));
15 |
16 | thFoo.Start();
17 | thBar.Start();
18 |
19 | // thFoo.Join();
20 | // thBar.Join();
21 |
22 | /*
23 | * We do not need to call thFoo.Join() and thBar.Join().
24 | * The reason is main thread will wait for the completion of all threads before app exits.
25 | */
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/csharp/demoex/demoex-async-future-a01.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * ASYNCHRONOUS PROGRAMMING WITH THE FUTURE/TASK
3 | */
4 | using System;
5 | using System.Threading.Tasks;
6 | #pragma warning disable CS1998
7 |
8 |
9 |
10 | class DemoExAsyncA01 : IRunnable
11 | {
12 | public async void run()
13 | {
14 | var task = doSomething("cleaning house");
15 |
16 | while (false == task.IsCompleted)
17 | {
18 | // Waiting...
19 | }
20 | }
21 |
22 |
23 | private async Task doSomething(string taskName)
24 |
25 | {
26 | Console.WriteLine("I am doing " + taskName);
27 | }
28 | }
29 |
30 |
31 |
32 | #pragma warning restore CS1998
33 |
--------------------------------------------------------------------------------
/cpp/cpp-boost/demo07-terminate.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | FORCING A THREAD TO TERMINATE (i.e. killing the thread)
3 | */
4 |
5 |
6 | #include
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | volatile bool isRunning;
14 |
15 |
16 |
17 | void doTask() {
18 | while (isRunning) {
19 | cout << "Running..." << endl;
20 | boost::this_thread::sleep_for(boost::chrono::seconds(2));
21 | }
22 | }
23 |
24 |
25 |
26 | int main() {
27 | isRunning = true;
28 | boost::thread th(&doTask);
29 |
30 | boost::this_thread::sleep_for(boost::chrono::seconds(6));
31 | isRunning = false;
32 |
33 | th.join();
34 | return 0;
35 | }
36 |
--------------------------------------------------------------------------------
/cpp/cpp-pthread/demo00.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | INTRODUCTION TO MULTITHREADING
3 | You should try running this app several times and see results.
4 | */
5 |
6 |
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | void* doTask(void*) {
14 | for (int i = 0; i < 300; ++i)
15 | cout << "B";
16 |
17 | pthread_exit(nullptr);
18 | return nullptr;
19 | }
20 |
21 |
22 |
23 | int main() {
24 | pthread_t tid;
25 | int ret = 0;
26 |
27 | ret = pthread_create(&tid, nullptr, &doTask, nullptr);
28 |
29 | for (int i = 0; i < 300; ++i)
30 | cout << "A";
31 |
32 | ret = pthread_join(tid, nullptr);
33 |
34 | cout << endl;
35 | return 0;
36 | }
37 |
--------------------------------------------------------------------------------
/csharp/demo/demo05-id.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * GETTING THREAD'S ID
3 | */
4 | using System;
5 | using System.Threading;
6 |
7 |
8 |
9 | class Demo05 : IRunnable
10 | {
11 | public void run()
12 | {
13 | ThreadStart doTask = () =>
14 | {
15 | int id = Thread.CurrentThread.ManagedThreadId;
16 | Console.WriteLine(id);
17 | };
18 |
19 | Thread thFoo = new Thread(doTask);
20 | Thread thBar = new Thread(doTask);
21 |
22 | Console.WriteLine("foo's id: " + thFoo.ManagedThreadId);
23 | Console.WriteLine("bar's id: " + thBar.ManagedThreadId);
24 |
25 | thFoo.Start();
26 | thBar.Start();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/cpp/cpp-boost/demo15a-deadlock.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | DEADLOCK
3 | Version A
4 | */
5 |
6 |
7 | #include
8 | #include
9 | #include
10 | using namespace std;
11 |
12 |
13 |
14 | boost::mutex mut;
15 |
16 |
17 |
18 | void doTask(std::string name) {
19 | mut.lock();
20 |
21 | cout << name << " acquired resource" << endl;
22 |
23 | // mut.unlock(); // Forget this statement ==> deadlock
24 | }
25 |
26 |
27 |
28 | int main() {
29 | boost::thread thFoo(&doTask, "foo");
30 | boost::thread thBar(&doTask, "bar");
31 |
32 | thFoo.join();
33 | thBar.join();
34 |
35 | cout << "You will never see this statement due to deadlock!" << endl;
36 | return 0;
37 | }
38 |
--------------------------------------------------------------------------------
/cpp/cpp-boost/demo25a-atomic.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | ATOMIC ACCESS
3 | */
4 |
5 |
6 | #include
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | volatile int counter = 0;
14 |
15 |
16 |
17 | void doTask() {
18 | boost::this_thread::sleep_for(boost::chrono::seconds(1));
19 | counter += 1;
20 | }
21 |
22 |
23 |
24 | int main() {
25 | counter = 0;
26 |
27 | boost::thread_group lstTh;
28 |
29 | for (int i = 0; i < 1000; ++i) {
30 | lstTh.add_thread(new boost::thread(&doTask));
31 | }
32 |
33 | lstTh.join_all();
34 |
35 | // Unpredictable result
36 | cout << "counter = " << counter << endl;
37 | return 0;
38 | }
39 |
--------------------------------------------------------------------------------
/cpp/cpp-std/demo12a-race-condition.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | RACE CONDITIONS
3 | */
4 |
5 |
6 | #include
7 | #include
8 | #include
9 | #include
10 | using namespace std;
11 |
12 |
13 |
14 | void doTask(int index) {
15 | std::this_thread::sleep_for(std::chrono::seconds(1));
16 | cout << index;
17 | }
18 |
19 |
20 |
21 | int main() {
22 | constexpr int NUM_THREADS = 4;
23 | vector lstTh;
24 |
25 | for (int i = 0; i < NUM_THREADS; ++i) {
26 | lstTh.push_back(
27 | std::thread(&doTask, i)
28 | );
29 | }
30 |
31 | for (auto&& th : lstTh) {
32 | th.join();
33 | }
34 |
35 | cout << endl;
36 | return 0;
37 | }
38 |
--------------------------------------------------------------------------------
/csharp/demo/demo03c-pass-arg.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * PASSING ARGUMENTS
3 | * Version C: Traditional way + dynamic data type
4 | */
5 | using System;
6 | using System.Threading;
7 |
8 |
9 |
10 | class Demo03B : IRunnable
11 | {
12 | public void run()
13 | {
14 | Thread thFoo = new Thread(doTask);
15 | Thread thBar = new Thread(doTask);
16 |
17 | thFoo.Start(new object[] { 1, 2, "red" });
18 | thBar.Start(new object[] { 3, 4, "blue" });
19 | }
20 |
21 | private void doTask(dynamic arg)
22 | {
23 | int a = arg[0];
24 | double b = arg[1];
25 | string c = arg[2];
26 | Console.WriteLine($"{a} {b} {c}\n");
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/python/demo22a_blocking_queue.py:
--------------------------------------------------------------------------------
1 | '''
2 | BLOCKING QUEUES
3 | Version A: A slow producer and a fast consumer
4 | '''
5 |
6 | import time
7 | from queue import Queue
8 | import threading
9 |
10 |
11 |
12 | def producer(q: Queue):
13 | time.sleep(2)
14 | q.put('Alice')
15 |
16 | time.sleep(2)
17 | q.put('likes')
18 |
19 | time.sleep(2)
20 | q.put('singing')
21 |
22 |
23 |
24 | def consumer(q: Queue):
25 | for _ in range(3):
26 | print('\nWaiting for data...')
27 | data = q.get()
28 | print(f' {data}')
29 |
30 |
31 |
32 | blkq = Queue()
33 |
34 | threading.Thread(target=producer, args=(blkq,)).start()
35 | threading.Thread(target=consumer, args=(blkq,)).start()
36 |
--------------------------------------------------------------------------------
/csharp/demo/demo12a-race-condition.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * RACE CONDITIONS
3 | */
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Threading;
7 |
8 |
9 |
10 | class Demo12A : IRunnable
11 | {
12 | public void run()
13 | {
14 | const int NUM_THREADS = 5;
15 | var lstTh = new List();
16 |
17 |
18 | for (int i = 0; i < NUM_THREADS; ++i)
19 | {
20 | int ith = i;
21 |
22 | lstTh.Add(new Thread(() =>
23 | {
24 | Thread.Sleep(1000);
25 | Console.WriteLine(ith);
26 | }));
27 | }
28 |
29 |
30 | lstTh.ForEach(th => th.Start());
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/csharp/demo/demo24-volatile.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * THE VOLATILE KEYWORD
3 | */
4 | using System;
5 | using System.Threading;
6 |
7 |
8 |
9 | class Demo24 : IRunnable
10 | {
11 | public void run()
12 | {
13 | Global.isRunning = true;
14 | new Thread(doTask).Start();
15 |
16 | Thread.Sleep(6000);
17 | Global.isRunning = false;
18 | }
19 |
20 |
21 | private void doTask()
22 | {
23 | while (Global.isRunning)
24 | {
25 | Console.WriteLine("Running...");
26 | Thread.Sleep(2000);
27 | }
28 | }
29 |
30 |
31 | class Global
32 | {
33 | public static volatile bool isRunning;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/cpp/cpp-std/demo09-detach.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | THREAD DETACHING
3 | */
4 |
5 |
6 | #include
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | void foo() {
14 | cout << "foo is starting..." << endl;
15 |
16 | std::this_thread::sleep_for(std::chrono::seconds(2));
17 |
18 | cout << "foo is exiting..." << endl;
19 | }
20 |
21 |
22 |
23 | int main() {
24 | auto thFoo = std::thread(&foo);
25 | thFoo.detach();
26 |
27 |
28 | // If I comment this statement,
29 | // thFoo will be forced into terminating with main thread
30 | std::this_thread::sleep_for(std::chrono::seconds(3));
31 |
32 |
33 | cout << "Main thread is exiting" << endl;
34 | return 0;
35 | }
36 |
--------------------------------------------------------------------------------
/cpp/cpp-std/demo15a-deadlock.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | DEADLOCK
3 | Version A
4 | */
5 |
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | using namespace std;
12 |
13 |
14 |
15 | std::mutex mut;
16 |
17 |
18 |
19 | void doTask(std::string name) {
20 | mut.lock();
21 |
22 | cout << name << " acquired resource" << endl;
23 |
24 | // mut.unlock(); // Forget this statement ==> deadlock
25 | }
26 |
27 |
28 |
29 | int main() {
30 | auto thFoo = std::thread(&doTask, "foo");
31 | auto thBar = std::thread(&doTask, "bar");
32 |
33 | thFoo.join();
34 | thBar.join();
35 |
36 | cout << "You will never see this statement due to deadlock!" << endl;
37 | return 0;
38 | }
39 |
--------------------------------------------------------------------------------
/python/demo13a_mutex.py:
--------------------------------------------------------------------------------
1 | '''
2 | MUTEXES
3 | In Python, Lock objects can be used as mutexes
4 | '''
5 |
6 | import time
7 | import threading
8 |
9 |
10 |
11 | mutex = threading.Lock()
12 | counter = 0
13 |
14 |
15 |
16 | def do_task():
17 | global counter
18 |
19 | mutex.acquire()
20 |
21 | for _ in range(1000):
22 | temp = counter + 1
23 | time.sleep(0.0001)
24 | counter = temp
25 |
26 | mutex.release()
27 |
28 |
29 |
30 | NUM_THREADS = 32
31 | lstth = [threading.Thread(target=do_task) for _ in range(NUM_THREADS)]
32 |
33 | for th in lstth:
34 | th.start()
35 |
36 | for th in lstth:
37 | th.join()
38 |
39 | print('counter =', counter)
40 | # We are sure that counter = 32000
41 |
--------------------------------------------------------------------------------
/cpp/cpp-pthread/demo24-volatile.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | THE VOLATILE KEYWORD
3 | */
4 |
5 |
6 | #include
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | volatile bool isRunning;
14 |
15 |
16 |
17 | void* doTask(void*) {
18 | while (isRunning) {
19 | cout << "Running..." << endl;
20 | sleep(2);
21 | }
22 |
23 | pthread_exit(nullptr);
24 | return nullptr;
25 | }
26 |
27 |
28 |
29 | int main() {
30 | pthread_t tid;
31 | int ret = 0;
32 |
33 | isRunning = true;
34 | ret = pthread_create(&tid, nullptr, &doTask, nullptr);
35 |
36 | sleep(6);
37 | isRunning = false;
38 |
39 | ret = pthread_join(tid, nullptr);
40 | return 0;
41 | }
42 |
--------------------------------------------------------------------------------
/js-nodejs/demo00.js:
--------------------------------------------------------------------------------
1 | /*
2 | INTRODUCTION TO MULTITHREADING
3 | You should try running this app several times and see results.
4 | */
5 |
6 | import * as mylib from './mylib.js';
7 | import { Worker, isMainThread } from 'worker_threads';
8 |
9 |
10 | const workerFunc = async () => {
11 | for (let i = 0; i < 300; ++i) {
12 | await mylib.sleep(1);
13 | process.stdout.write('B');
14 | }
15 | };
16 |
17 |
18 | const mainFunc = async () => {
19 | const worker = new Worker(new URL(import.meta.url));
20 |
21 | for (let i = 0; i < 300; ++i) {
22 | await mylib.sleep(1);
23 | process.stdout.write('A');
24 | }
25 | };
26 |
27 |
28 | if (isMainThread) {
29 | await mainFunc();
30 | } else {
31 | await workerFunc();
32 | }
33 |
--------------------------------------------------------------------------------
/python/demo20a01_semaphore.py:
--------------------------------------------------------------------------------
1 | '''
2 | SEMAPHORES
3 | Version A: Paper sheets and packages
4 | '''
5 |
6 | import time
7 | import threading
8 |
9 |
10 |
11 | sem_package = threading.Semaphore(0)
12 |
13 |
14 |
15 | def make_one_sheet():
16 | for _ in range(4):
17 | print('Make 1 sheet')
18 | time.sleep(1)
19 | sem_package.release()
20 |
21 |
22 |
23 | def combine_one_package():
24 | for _ in range(4):
25 | sem_package.acquire()
26 | sem_package.acquire()
27 | print('Combine 2 sheets into 1 package')
28 |
29 |
30 |
31 | threading.Thread(target=make_one_sheet).start()
32 | threading.Thread(target=make_one_sheet).start()
33 | threading.Thread(target=combine_one_package).start()
34 |
--------------------------------------------------------------------------------
/python/demo12b02_data_race_multi.py:
--------------------------------------------------------------------------------
1 | '''
2 | DATA RACES
3 | Version 02: Multithreading
4 | '''
5 |
6 | import threading
7 |
8 |
9 |
10 | def count_div_2(a: list, n: int):
11 | for i in range(2, n + 1, 2):
12 | a[i] = True
13 |
14 |
15 |
16 | def count_div_3(a: list, n: int):
17 | for i in range(3, n + 1, 3):
18 | a[i] = True
19 |
20 |
21 |
22 | N = 8
23 | A = [False] * (N + 1)
24 |
25 | th_div_2 = threading.Thread(target=count_div_2, args=(A, N))
26 | th_div_3 = threading.Thread(target=count_div_3, args=(A, N))
27 |
28 | th_div_2.start()
29 | th_div_3.start()
30 | th_div_2.join()
31 | th_div_3.join()
32 |
33 | result = A.count(True)
34 |
35 | print('Number of integers that are divisible by 2 or 3 is:', result)
36 |
--------------------------------------------------------------------------------
/cpp/cpp-boost/demo01b-hello-class02.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | HELLO WORLD VERSION MULTITHREADING
3 | Version B: Using class methods
4 | */
5 |
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | using namespace std;
12 |
13 |
14 |
15 | class Example {
16 | public:
17 | void run() {
18 | boost::thread th(&Example::doTask, this, "Good day");
19 | // boost::thread th(boost::bind(&Example::doTask, this, "Good day"));
20 | th.join();
21 | }
22 |
23 | private:
24 | void doTask(string message) {
25 | cout << message << endl;
26 | }
27 | };
28 |
29 |
30 |
31 | int main() {
32 | Example example;
33 | example.run();
34 | return 0;
35 | }
36 |
--------------------------------------------------------------------------------
/cpp/cpp-pthread/exer05-util.hpp:
--------------------------------------------------------------------------------
1 | #ifndef _EXER05_UTIL_HPP_
2 | #define _EXER05_UTIL_HPP_
3 |
4 |
5 |
6 | struct WorkerScProdArg {
7 | double const* u = nullptr;
8 | double const* v = nullptr;
9 | int sizeVector = 0;
10 | double* res = nullptr;
11 | };
12 |
13 |
14 |
15 | void* workerScalarProduct(void* argVoid) {
16 | auto arg = (WorkerScProdArg*) argVoid;
17 | auto u = arg->u;
18 | auto v = arg->v;
19 | auto sizeVector = arg->sizeVector;
20 | auto res = arg->res;
21 |
22 | double sum = 0;
23 |
24 | for (int i = sizeVector - 1; i >= 0; --i) {
25 | sum += u[i] * v[i];
26 | }
27 |
28 | (*res) = sum;
29 |
30 | return nullptr;
31 | }
32 |
33 |
34 |
35 | #endif // _EXER05_UTIL_HPP_
36 |
--------------------------------------------------------------------------------
/csharp/demoex/demoex-async-future-a02.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * ASYNCHRONOUS PROGRAMMING WITH THE FUTURE/TASK
3 | */
4 | using System;
5 | using System.Threading.Tasks;
6 | #pragma warning disable CS1998
7 |
8 |
9 |
10 | class DemoExAsyncA02 : IRunnable
11 | {
12 | public async void run()
13 | {
14 | var task = getSquared(7);
15 |
16 | while (false == task.IsCompleted)
17 | {
18 | // Waiting...
19 | }
20 |
21 | int result = await task;
22 | Console.WriteLine(result);
23 | }
24 |
25 |
26 |
27 | private async Task getSquared(int x)
28 |
29 | {
30 | return x * x;
31 | }
32 | }
33 |
34 |
35 |
36 | #pragma warning restore CS1998
37 |
--------------------------------------------------------------------------------
/cpp/cpp-boost/demo25b-atomic.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | ATOMIC ACCESS
3 | */
4 |
5 |
6 | #include
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | // boost::atomic counter;
14 | boost::atomic_int32_t counter;
15 |
16 |
17 |
18 | void doTask() {
19 | boost::this_thread::sleep_for(boost::chrono::seconds(1));
20 | counter += 1;
21 | }
22 |
23 |
24 |
25 | int main() {
26 | counter = 0;
27 |
28 | boost::thread_group lstTh;
29 |
30 | for (int i = 0; i < 1000; ++i) {
31 | lstTh.add_thread(new boost::thread(&doTask));
32 | }
33 |
34 | lstTh.join_all();
35 |
36 | // counter = 1000
37 | cout << "counter = " << counter << endl;
38 | return 0;
39 | }
40 |
--------------------------------------------------------------------------------
/cpp/cpp-pthread/demo07b-terminate.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | FORCING A THREAD TO TERMINATE (i.e. killing the thread)
3 | Version B: Using pthread_cancel
4 | */
5 |
6 |
7 | #include
8 | #include
9 | #include
10 | using namespace std;
11 |
12 |
13 |
14 | void* doTask(void*) {
15 | while (1) {
16 | cout << "Running..." << endl;
17 | sleep(1);
18 | }
19 |
20 | pthread_exit(nullptr);
21 | return nullptr;
22 | }
23 |
24 |
25 |
26 | int main() {
27 | pthread_t tid;
28 | int ret = 0;
29 |
30 | ret = pthread_create(&tid, nullptr, &doTask, nullptr);
31 |
32 | sleep(3);
33 |
34 | ret = pthread_cancel(tid);
35 |
36 | ret = pthread_join(tid, nullptr);
37 |
38 | return 0;
39 | }
40 |
--------------------------------------------------------------------------------
/cpp/cpp-std/demo25a-atomic.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | ATOMIC ACCESS
3 | */
4 |
5 |
6 | #include
7 | #include
8 | #include
9 | #include
10 | using namespace std;
11 |
12 |
13 |
14 | volatile int counter = 0;
15 |
16 |
17 |
18 | void doTask() {
19 | std::this_thread::sleep_for(std::chrono::seconds(1));
20 | counter += 1;
21 | }
22 |
23 |
24 |
25 | int main() {
26 | counter = 0;
27 |
28 | vector lstTh;
29 |
30 | for (int i = 0; i < 1000; ++i) {
31 | lstTh.push_back(std::thread(&doTask));
32 | }
33 |
34 | for (auto&& th : lstTh) {
35 | th.join();
36 | }
37 |
38 | // Unpredictable result
39 | cout << "counter = " << counter << endl;
40 | return 0;
41 | }
42 |
--------------------------------------------------------------------------------
/js-nodejs/exerex-userhash-util.js:
--------------------------------------------------------------------------------
1 | const { createHash } = await import('node:crypto');
2 |
3 |
4 | export const getHash = (numLoops, str) => {
5 | for (let i = numLoops; i > 0; --i) {
6 | str = createHash('sha256').update(str).digest('hex');
7 | }
8 | return str;
9 | };
10 |
11 |
12 | export const splitStrInToChunks = (numChunks, str) => {
13 | const lstChunks = [];
14 | const quotient = Math.floor(str.length / numChunks);
15 | const remainder = str.length % numChunks;
16 | for (let i = 0; i < numChunks; ++i) {
17 | const chunk = str.substring(
18 | i * quotient + Math.min(i, remainder),
19 | (i+1) * quotient + Math.min(i+1, remainder)
20 | );
21 | lstChunks.push(chunk);
22 | }
23 | return lstChunks;
24 | };
25 |
--------------------------------------------------------------------------------
/cpp/cpp-boost/demo09-detach.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | THREAD DETACHING
3 | */
4 |
5 |
6 | #include
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | void foo() {
14 | cout << "foo is starting..." << endl;
15 |
16 | boost::this_thread::sleep_for(boost::chrono::seconds(2));
17 |
18 | cout << "foo is exiting..." << endl;
19 | }
20 |
21 |
22 |
23 | int main() {
24 | boost::thread thFoo(&foo);
25 | thFoo.detach();
26 |
27 |
28 | // If I comment this statement,
29 | // thFoo will be forced into terminating with main thread
30 | boost::this_thread::sleep_for(boost::chrono::seconds(3));
31 |
32 |
33 | cout << "Main thread is exiting" << endl;
34 | return 0;
35 | }
36 |
--------------------------------------------------------------------------------
/csharp/demo/demo09-detach.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * THREAD DETACHING
3 | */
4 | using System;
5 | using System.Threading;
6 |
7 |
8 |
9 | class Demo09 : IRunnable
10 | {
11 | public void run()
12 | {
13 | var thFoo = new Thread(() => {
14 | Console.WriteLine("foo is starting...");
15 | Thread.Sleep(2000);
16 | Console.WriteLine("foo is exiting...");
17 | });
18 |
19 |
20 | thFoo.IsBackground = true;
21 | thFoo.Start();
22 |
23 |
24 | // If I comment this statement,
25 | // thFoo will be forced into terminating with main thread
26 | Thread.Sleep(3000);
27 |
28 |
29 | Console.WriteLine("Main thread is exiting");
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/java/src/demo01_hello/AppB01.java:
--------------------------------------------------------------------------------
1 | /*
2 | * HELLO WORLD VERSION MULTITHREADING
3 | * Version B01: Using inteface Runnable
4 | */
5 |
6 | package demo01_hello;
7 |
8 |
9 |
10 | public class AppB01 {
11 |
12 | public static void main(String[] args) throws InterruptedException {
13 | var doTask = new ExampleRunnable();
14 |
15 | var th1 = new Thread(doTask);
16 | var th2 = new Thread(doTask);
17 |
18 | th1.start();
19 | th2.start();
20 |
21 | System.out.println("Hello from main thread");
22 | }
23 |
24 | }
25 |
26 |
27 |
28 | class ExampleRunnable implements Runnable {
29 | @Override
30 | public void run() {
31 | System.out.println("Hello from example thread");
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/java/src/demo06_list_threads/AppB01.java:
--------------------------------------------------------------------------------
1 | /*
2 | * LIST OF MULTIPLE THREADS
3 | * Version B01: Using streams
4 | */
5 |
6 | package demo06_list_threads;
7 |
8 | import java.util.stream.IntStream;
9 |
10 |
11 |
12 | public class AppB01 {
13 |
14 | public static void main(String[] args) {
15 | var lstTh = IntStream.range(0, 5).mapToObj(i -> new Thread(() -> {
16 |
17 | try { Thread.sleep(500); }
18 | catch (InterruptedException e) { }
19 |
20 | System.out.print(i);
21 |
22 | })).toList();
23 |
24 |
25 | for (var th : lstTh)
26 | th.start();
27 |
28 | // We can reduce above for loop with this statement:
29 | // lstTh.forEach(Thread::start);
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/python/exer01a_max_div.py:
--------------------------------------------------------------------------------
1 | '''
2 | MAXIMUM NUMBER OF DIVISORS
3 | '''
4 |
5 | import time
6 |
7 |
8 |
9 | RANGE_START = 1
10 | RANGE_END = 30000
11 |
12 | res_value = 0
13 | res_numdiv = 0 # number of divisors of result
14 |
15 | tp_start = time.time()
16 |
17 |
18 | for i in range(RANGE_START, RANGE_END + 1):
19 | numdiv = 0
20 |
21 | for j in range(1, i // 2):
22 | if i % j == 0:
23 | numdiv += 1
24 |
25 | if res_numdiv < numdiv:
26 | res_numdiv = numdiv
27 | res_value = i
28 |
29 |
30 | time_elapsed = time.time() - tp_start
31 |
32 | print('The integer which has largest number of divisors is', res_value)
33 | print('The largest number of divisor is', res_numdiv)
34 | print('Time elapsed =', time_elapsed)
35 |
--------------------------------------------------------------------------------
/python/demo18a03_barrier.py:
--------------------------------------------------------------------------------
1 | '''
2 | BARRIERS AND LATCHES
3 | Version A: Barriers
4 | '''
5 |
6 | import time
7 | import threading
8 |
9 |
10 |
11 | sync_point_a = threading.Barrier(parties=2)
12 | sync_point_b = threading.Barrier(parties=2)
13 |
14 |
15 |
16 | def process_request(user_name: str, wait_time: int):
17 | time.sleep(wait_time)
18 |
19 | print(f'Get request from {user_name}')
20 | sync_point_a.wait()
21 |
22 | print(f'Process request for {user_name}')
23 | sync_point_b.wait()
24 |
25 | print(f'Done {user_name}')
26 |
27 |
28 |
29 | lstarg = [
30 | ('lorem', 1),
31 | ('ipsum', 3),
32 | ('dolor', 3),
33 | ('amet', 10)
34 | ]
35 |
36 | _ = [ threading.Thread(target=process_request, args=arg) for arg in lstarg ]
37 |
--------------------------------------------------------------------------------
/python/exer02a02_producer_consumer.py:
--------------------------------------------------------------------------------
1 | '''
2 | THE PRODUCER-CONSUMER PROBLEM
3 |
4 | SOLUTION TYPE A: USING BLOCKING QUEUES
5 | Version A02: 2 slow producers, 1 fast consumer
6 | '''
7 |
8 | import time
9 | from queue import Queue
10 | import threading
11 |
12 |
13 |
14 | def producer(q: Queue):
15 | i = 1
16 |
17 | while True:
18 | q.put(i)
19 | time.sleep(1)
20 | i += 1
21 |
22 |
23 |
24 | def consumer(q: Queue):
25 | while True:
26 | data = q.get()
27 | print('Consumer', data)
28 |
29 |
30 |
31 | blkq = Queue()
32 |
33 | threading.Thread(target=producer, args=(blkq,)).start()
34 | threading.Thread(target=producer, args=(blkq,)).start()
35 |
36 | threading.Thread(target=consumer, args=(blkq,)).start()
37 |
--------------------------------------------------------------------------------
/java/src/demo01_hello/AppExtra.java:
--------------------------------------------------------------------------------
1 | /*
2 | * HELLO WORLD VERSION MULTITHREADING
3 | * Version extra: Getting thread name and reference to thread instance executing current thread
4 | */
5 |
6 | package demo01_hello;
7 |
8 |
9 |
10 | public class AppExtra {
11 |
12 | public static void main(String[] args) throws InterruptedException {
13 | var th = new Thread("Lorem") {
14 | @Override
15 | public void run() {
16 | Thread myself = Thread.currentThread(); // th is myself
17 |
18 | System.out.println("My name is " + this.getName()); // or myself.getName()
19 | System.out.println("My self is " + myself);
20 | }
21 | };
22 |
23 | th.start();
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/java/src/demo24_volatile/App.java:
--------------------------------------------------------------------------------
1 | /*
2 | * THE VOLATILE KEYWORD
3 | */
4 |
5 | package demo24_volatile;
6 |
7 |
8 |
9 | public class App {
10 |
11 | public static void main(String[] args) throws InterruptedException {
12 | Global.isRunning = true;
13 | new Thread(() -> doTask()).start();
14 |
15 | Thread.sleep(6000);
16 | Global.isRunning = false;
17 | }
18 |
19 |
20 | private static void doTask() {
21 | while (Global.isRunning) {
22 | System.out.println("Running...");
23 | try { Thread.sleep(2000); } catch (InterruptedException e) { }
24 | }
25 | }
26 |
27 |
28 |
29 | private static class Global {
30 | public static volatile boolean isRunning;
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/python/demo18a02_barrier.py:
--------------------------------------------------------------------------------
1 | '''
2 | BARRIERS AND LATCHES
3 | Version A: Barriers
4 | '''
5 |
6 | import time
7 | import threading
8 |
9 |
10 |
11 | sync_point = threading.Barrier(parties=2)
12 |
13 |
14 |
15 | def process_request(user_name: str, wait_time: int):
16 | time.sleep(wait_time)
17 |
18 | print(f'Get request from {user_name}')
19 | sync_point.wait()
20 |
21 | print(f'Process request for {user_name}')
22 | sync_point.wait()
23 |
24 | print(f'Done {user_name}')
25 |
26 |
27 |
28 | lstarg = [
29 | ('lorem', 1),
30 | ('ipsum', 3),
31 | ('dolor', 3),
32 | ('amet', 10)
33 | ]
34 |
35 | _ = [ threading.Thread(target=process_request, args=arg) for arg in lstarg ]
36 |
37 | # Thread with user_name = "amet" shall be FREEZED
38 |
--------------------------------------------------------------------------------
/cpp/cpp-boost/demo03c-pass-arg.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | PASSING ARGUMENTS
3 | Version C: Passing normal references
4 | */
5 |
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | using namespace std;
12 |
13 |
14 |
15 | void doTask(string& msg) {
16 | cout << msg << endl;
17 | }
18 |
19 |
20 |
21 | int main() {
22 | string a = "lorem ipsum";
23 | string b = "dolor amet";
24 |
25 | // We should use boost:ref to pass references
26 | boost::thread thFoo(&doTask, boost::ref(a));
27 | boost::thread thBar(&doTask, boost::ref(b));
28 |
29 | // boost::thread thFoo(&doTask, a);
30 | // boost::thread thBar(&doTask, b);
31 |
32 | thFoo.join();
33 | thBar.join();
34 |
35 | return 0;
36 | }
37 |
--------------------------------------------------------------------------------
/old/cppstd-reentrant-lock-b.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | REENTRANT LOCK (RECURSIVE MUTEX)
3 | */
4 |
5 |
6 | #include
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | std::recursive_mutex mut;
14 |
15 |
16 |
17 | int getFactorial(int n) {
18 | if (n <= 0)
19 | return 1;
20 |
21 | mut.lock();
22 |
23 | int result = n * getFactorial(n - 1);
24 |
25 | mut.unlock();
26 |
27 | return result;
28 | }
29 |
30 |
31 |
32 | void routine(int n) {
33 | int factorial = getFactorial(n);
34 | cout << "Factorial of " << n << " is " << factorial << endl;
35 | }
36 |
37 |
38 |
39 | int main() {
40 | int n = 5;
41 |
42 | auto th = std::thread(routine, n);
43 |
44 | th.join();
45 |
46 | return 0;
47 | }
48 |
--------------------------------------------------------------------------------
/python/demo23b_thread_local.py:
--------------------------------------------------------------------------------
1 | '''
2 | THREAD-LOCAL STORAGE
3 | Avoiding synchronization using thread-local storage
4 | '''
5 |
6 | import time
7 | import threading
8 |
9 |
10 |
11 | data = threading.local()
12 |
13 |
14 |
15 | def do_task(t: int):
16 | time.sleep(1)
17 | data.counter = 0
18 |
19 | for _ in range(1000):
20 | data.counter += 1
21 |
22 | print(f'Thread {t} gives counter = {data.counter}')
23 |
24 |
25 |
26 | NUM_THREADS = 3
27 |
28 | for i in range(NUM_THREADS):
29 | threading.Thread(target=do_task, args=(i,)).start()
30 |
31 | # By using thread-local storage, each thread has its own counter.
32 | # So, the counter in one thread is completely independent of each other.
33 | # Thread-local storage helps us to AVOID SYNCHRONIZATION.
34 |
--------------------------------------------------------------------------------
/cpp/cpp-boost/demo17a-reentrant-lock.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | REENTRANT LOCKS (RECURSIVE MUTEXES)
3 | Version A: Introduction to reentrant locks
4 | */
5 |
6 |
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | boost::mutex mut;
14 |
15 |
16 |
17 | void doTask() {
18 | mut.lock();
19 | cout << "First time acquiring the resource" << endl;
20 |
21 | mut.lock();
22 | cout << "Second time acquiring the resource" << endl;
23 |
24 | mut.unlock();
25 | mut.unlock();
26 | }
27 |
28 |
29 |
30 | int main() {
31 | boost::thread th(&doTask);
32 | /*
33 | The thread th shall meet deadlock.
34 | So, you will never get output "Second time the acquiring resource".
35 | */
36 | th.join();
37 | return 0;
38 | }
39 |
--------------------------------------------------------------------------------
/java/src/demo17_reentrant_lock/AppA01.java:
--------------------------------------------------------------------------------
1 | /*
2 | * REENTRANT LOCKS (RECURSIVE MUTEXES)
3 | * Version A01: A simple example
4 | */
5 |
6 | package demo17_reentrant_lock;
7 |
8 | import java.util.concurrent.locks.Lock;
9 | import java.util.concurrent.locks.ReentrantLock;
10 |
11 |
12 |
13 | public class AppA01 {
14 |
15 | public static void main(String[] args) {
16 | Lock lk = new ReentrantLock();
17 |
18 |
19 | new Thread(() -> {
20 |
21 | lk.lock();
22 | System.out.println("First time acquiring the resource");
23 |
24 | lk.lock();
25 | System.out.println("Second time acquiring the resource");
26 |
27 | lk.unlock();
28 | lk.unlock();
29 |
30 | }).start();
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/cpp/cpp-pthread/demo23a-thread-local.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | THREAD-LOCAL STORAGE
3 | Introduction
4 |
5 | The code is specific for gcc.
6 | */
7 |
8 |
9 | #include
10 | #include
11 | using namespace std;
12 |
13 |
14 |
15 | __thread int value = 123;
16 |
17 |
18 |
19 | void* doTask(void* arg) {
20 | cout << value << endl;
21 | pthread_exit(nullptr);
22 | return nullptr;
23 | }
24 |
25 |
26 |
27 | int main() {
28 | pthread_t tid;
29 | int ret = 0;
30 |
31 | // Main thread sets value = 999
32 | value = 999;
33 | cout << value << endl;
34 |
35 | // Child thread gets value
36 | // Expected output: 123
37 | ret = pthread_create(&tid, nullptr, &doTask, nullptr);
38 | ret = pthread_join(tid, nullptr);
39 |
40 | return 0;
41 | }
42 |
--------------------------------------------------------------------------------
/cpp/cpp-pthread/demo03a02-pass-arg.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | PASSING ARGUMENTS
3 | Version A02: Solving the problem
4 | */
5 |
6 |
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | void* doTask(void* ptrId) {
14 | int id = *(int*)ptrId;
15 |
16 | cout << "Hello pthread with id = " << id << endl;
17 |
18 | pthread_exit(nullptr);
19 | return nullptr;
20 | }
21 |
22 |
23 |
24 | int main() {
25 | pthread_t lstTid[2];
26 | int lstArg[2];
27 | int ret = 0;
28 |
29 | for (int i = 0; i < 2; ++i) {
30 | lstArg[i] = i + 1;
31 | ret = pthread_create(&lstTid[i], nullptr, &doTask, &lstArg[i]);
32 | }
33 |
34 | for (int i = 0; i < 2; ++i)
35 | ret = pthread_join(lstTid[i], nullptr);
36 |
37 | return 0;
38 | }
39 |
--------------------------------------------------------------------------------
/csharp/demo/demo10-yield.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * THREAD YIELDING
3 | */
4 | using System;
5 | using System.Threading;
6 |
7 |
8 |
9 | class Demo10 : IRunnable
10 | {
11 | public void run()
12 | {
13 | DateTime tpStartMeasure = DateTime.Now;
14 |
15 | littleSleep(1);
16 |
17 | var timeElapsed = DateTime.Now.Subtract(tpStartMeasure).TotalMilliseconds;
18 |
19 | Console.WriteLine($"Elapsed time: {timeElapsed} miliseonds");
20 | }
21 |
22 |
23 | private void littleSleep(double miliseconds)
24 | {
25 | DateTime tpEnd = DateTime.Now.AddMilliseconds(miliseconds);
26 |
27 | do
28 | {
29 | Thread.Yield();
30 | }
31 | while (DateTime.Now.CompareTo(tpEnd) < 0);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/csharp/demoex/demoex-async-future-c01.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * ASYNCHRONOUS PROGRAMMING WITH THE FUTURE/TASK
3 | */
4 | using System;
5 | using System.Threading.Tasks;
6 |
7 |
8 |
9 | class DemoExAsyncC01 : IRunnable
10 | {
11 | public void run()
12 | {
13 | var task = getSquared(7)
14 | .ContinueWith((previousTask) => getDiv2(previousTask.Result))
15 | .Unwrap();
16 |
17 | int result = task.Result;
18 | Console.WriteLine(result);
19 | }
20 |
21 | private async Task getSquared(int x)
22 | {
23 | await Task.Delay(100);
24 | return x * x;
25 | }
26 |
27 | private async Task getDiv2(int x)
28 | {
29 | await Task.Delay(100);
30 | return x / 2;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/python/exer02a03_producer_consumer.py:
--------------------------------------------------------------------------------
1 | '''
2 | THE PRODUCER-CONSUMER PROBLEM
3 |
4 | SOLUTION TYPE A: USING BLOCKING QUEUES
5 | Version A03: 1 slow producer, 2 fast consumers
6 | '''
7 |
8 | import time
9 | from queue import Queue
10 | import threading
11 |
12 |
13 |
14 | def producer(q: Queue):
15 | i = 1
16 |
17 | while True:
18 | q.put(i)
19 | time.sleep(1)
20 | i += 1
21 |
22 |
23 |
24 | def consumer(name: str, q: Queue):
25 | while True:
26 | data = q.get()
27 | print(f'Consumer {name}: {data}')
28 |
29 |
30 |
31 | blkq = Queue()
32 |
33 | threading.Thread(target=producer, args=(blkq,)).start()
34 |
35 | threading.Thread(target=consumer, args=('foo', blkq)).start()
36 | threading.Thread(target=consumer, args=('bar', blkq)).start()
37 |
--------------------------------------------------------------------------------
/cpp/cpp-pthread/demo05-id.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | GETTING THREAD'S ID
3 | */
4 |
5 |
6 | #include
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | void* doTask(void*) {
14 | sleep(2);
15 | cout << pthread_self() << endl;
16 |
17 | pthread_exit(nullptr);
18 | return nullptr;
19 | }
20 |
21 |
22 |
23 | int main() {
24 | pthread_t tidFoo, tidBar;
25 | int ret = 0;
26 |
27 | ret = pthread_create(&tidFoo, nullptr, &doTask, nullptr);
28 | ret = pthread_create(&tidBar, nullptr, &doTask, nullptr);
29 |
30 | cout << "foo's id = " << tidFoo << endl;
31 | cout << "bar's id = " << tidBar << endl;
32 |
33 | ret = pthread_join(tidFoo, nullptr);
34 | ret = pthread_join(tidBar, nullptr);
35 |
36 | return 0;
37 | }
38 |
--------------------------------------------------------------------------------
/cpp/cpp-std/demo17a-reentrant-lock.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | REENTRANT LOCKS (RECURSIVE MUTEXES)
3 | Version A: Introduction to reentrant locks
4 | */
5 |
6 |
7 | #include
8 | #include
9 | #include
10 | using namespace std;
11 |
12 |
13 |
14 | std::mutex mut;
15 |
16 |
17 |
18 | void doTask() {
19 | mut.lock();
20 | cout << "First time acquiring the resource" << endl;
21 |
22 | mut.lock();
23 | cout << "Second time acquiring the resource" << endl;
24 |
25 | mut.unlock();
26 | mut.unlock();
27 | }
28 |
29 |
30 |
31 | int main() {
32 | auto th = std::thread(&doTask);
33 | /*
34 | The thread th shall meet deadlock.
35 | So, you will never get output "Second time the acquiring resource".
36 | */
37 | th.join();
38 | return 0;
39 | }
40 |
--------------------------------------------------------------------------------
/csharp/demo/demo11c-exec-service.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * EXECUTOR SERVICES AND THREAD POOLS
3 | * Version C: Fixed thread pools
4 | */
5 | using System;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 |
9 |
10 |
11 | class Demo11C : IRunnable
12 | {
13 | public void run()
14 | {
15 | const int N = 5;
16 |
17 | var prlOptions = new ParallelOptions { MaxDegreeOfParallelism = 2 };
18 |
19 | Parallel.For(0, N, prlOptions,
20 | i =>
21 | {
22 | char name = (char)(i + 'A');
23 | Console.WriteLine($"Task {name} is starting");
24 | Thread.Sleep(3000);
25 | Console.WriteLine($"Task {name} is completed");
26 | }
27 | );
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/cpp/cpp-std/demo25b-atomic.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | ATOMIC ACCESS
3 | */
4 |
5 |
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | using namespace std;
12 |
13 |
14 |
15 | // std::atomic counter;
16 | std::atomic_int32_t counter;
17 |
18 |
19 |
20 | void doTask() {
21 | std::this_thread::sleep_for(std::chrono::seconds(1));
22 | counter += 1;
23 | }
24 |
25 |
26 |
27 | int main() {
28 | counter = 0;
29 |
30 | vector lstTh;
31 |
32 | for (int i = 0; i < 1000; ++i) {
33 | lstTh.push_back(std::thread(&doTask));
34 | }
35 |
36 | for (auto&& th : lstTh) {
37 | th.join();
38 | }
39 |
40 | // counter = 1000
41 | cout << "counter = " << counter << endl;
42 | return 0;
43 | }
44 |
--------------------------------------------------------------------------------
/java/src/demo09_detach/App.java:
--------------------------------------------------------------------------------
1 | /*
2 | * THREAD DETACHING
3 | */
4 |
5 | package demo09_detach;
6 |
7 |
8 |
9 | public class App {
10 |
11 | public static void main(String[] args) throws InterruptedException {
12 | var thFoo = new Thread(() -> {
13 | System.out.println("foo is starting...");
14 |
15 | try { Thread.sleep(2000); } catch (InterruptedException e) { }
16 |
17 | System.out.println("foo is exiting...");
18 | });
19 |
20 |
21 | thFoo.setDaemon(true);
22 | thFoo.start();
23 |
24 |
25 | // If I comment this statement,
26 | // thFoo will be forced into terminating with main thread
27 | Thread.sleep(3000);
28 |
29 |
30 | System.out.println("Main thread is exiting");
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/python/demo18b01_latch.py:
--------------------------------------------------------------------------------
1 | '''
2 | BARRIERS AND LATCHES
3 | Version B: Count-down latches
4 |
5 | Count-down latches in Python are not supported by default.
6 | So, I use mylib_latch for this demonstration.
7 | '''
8 |
9 | import time
10 | import threading
11 | from mylib_latch import CountDownLatch
12 |
13 |
14 |
15 | def process_request(user_name: str, wait_time: int):
16 | time.sleep(wait_time)
17 |
18 | print(f'Get request from {user_name}')
19 |
20 | sync_point.count_down()
21 | sync_point.wait()
22 |
23 | print(f'Done {user_name}')
24 |
25 |
26 |
27 | lstarg = [
28 | ('lorem', 1),
29 | ('ipsum', 2),
30 | ('dolor', 3)
31 | ]
32 |
33 | sync_point = CountDownLatch(count=3)
34 |
35 | _ = [ threading.Thread(target=process_request, args=arg).start() for arg in lstarg ]
36 |
--------------------------------------------------------------------------------
/cpp/cpp-pthread/demo09b-detach.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | THREAD DETACHING
3 | */
4 |
5 |
6 | #include
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | void* foo(void*) {
14 | int ret = 0;
15 |
16 | cout << "foo is starting..." << endl;
17 |
18 | if ( ret = pthread_detach(pthread_self()) ) {
19 | cout << "Error: Cannot detach" << endl;
20 | }
21 |
22 | sleep(2);
23 |
24 | cout << "foo is exiting..." << endl;
25 |
26 | pthread_exit(nullptr);
27 | return nullptr;
28 | }
29 |
30 |
31 |
32 | int main() {
33 | pthread_t tidFoo;
34 | int ret = 0;
35 |
36 | ret = pthread_create(&tidFoo, nullptr, &foo, nullptr);
37 |
38 | sleep(3);
39 |
40 | cout << "Main thread is exiting" << endl;
41 | return 0;
42 | }
43 |
--------------------------------------------------------------------------------
/csharp/demo/demo08a-return-value.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * GETTING RETURNED VALUES FROM THREADS
3 | */
4 | using System;
5 | using System.Threading;
6 |
7 |
8 |
9 | class Demo08A : IRunnable
10 | {
11 | public void run()
12 | {
13 | int resFoo = 0, resBar = 0;
14 |
15 | var thFoo = new Thread(() => resFoo = doubleValue(5));
16 | var thBar = new Thread(() => resBar = doubleValue(80));
17 |
18 | thFoo.Start();
19 | thBar.Start();
20 |
21 | // Wait until thFoo and thBar finish
22 | thFoo.Join();
23 | thBar.Join();
24 |
25 | Console.WriteLine(resFoo);
26 | Console.WriteLine(resBar);
27 | }
28 |
29 |
30 | private int doubleValue(int value)
31 | {
32 | return value * 2;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/cpp/cpp-boost/demo12b01-data-race-single.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | DATA RACES
3 | Version 01: Without multithreading
4 | */
5 |
6 |
7 | #include
8 | #include
9 | #include
10 | using namespace std;
11 |
12 |
13 |
14 | int getResult(int N) {
15 | vector a;
16 | a.resize(N + 1, false);
17 |
18 | for (int i = 1; i <= N; ++i)
19 | if (0 == i % 2 || 0 == i % 3)
20 | a[i] = true;
21 |
22 | // result = sum of a (i.e. counting number of true values in a)
23 | int result = std::accumulate(a.begin(), a.end(), 0);
24 | return result;
25 | }
26 |
27 |
28 |
29 | int main() {
30 | const int N = 8;
31 |
32 | int result = getResult(N);
33 |
34 | cout << "Number of integers that are divisible by 2 or 3 is: " << result << endl;
35 | return 0;
36 | }
37 |
--------------------------------------------------------------------------------
/cpp/cpp-pthread/demo07a-terminate.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | FORCING A THREAD TO TERMINATE (i.e. killing the thread)
3 | Version A: Using the flag 'isRunning'
4 | */
5 |
6 |
7 | #include
8 | #include
9 | #include
10 | using namespace std;
11 |
12 |
13 |
14 | volatile bool isRunning;
15 |
16 |
17 |
18 | void* doTask(void*) {
19 | while (isRunning) {
20 | cout << "Running..." << endl;
21 | sleep(2);
22 | }
23 |
24 | pthread_exit(nullptr);
25 | return nullptr;
26 | }
27 |
28 |
29 |
30 | int main() {
31 | pthread_t tid;
32 | int ret = 0;
33 |
34 | isRunning = true;
35 | ret = pthread_create(&tid, nullptr, &doTask, nullptr);
36 |
37 | sleep(6);
38 | isRunning = false;
39 |
40 | ret = pthread_join(tid, nullptr);
41 | return 0;
42 | }
43 |
--------------------------------------------------------------------------------
/cpp/cpp-std/demo12b01-data-race-single.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | DATA RACES
3 | Version 01: Without multithreading
4 | */
5 |
6 |
7 | #include
8 | #include
9 | #include
10 | using namespace std;
11 |
12 |
13 |
14 | int getResult(int N) {
15 | vector a;
16 | a.resize(N + 1, false);
17 |
18 | for (int i = 1; i <= N; ++i)
19 | if (0 == i % 2 || 0 == i % 3)
20 | a[i] = true;
21 |
22 | // result = sum of a (i.e. counting number of true values in a)
23 | int result = std::accumulate(a.begin(), a.end(), 0);
24 | return result;
25 | }
26 |
27 |
28 |
29 | int main() {
30 | constexpr int N = 8;
31 |
32 | int result = getResult(N);
33 |
34 | cout << "Number of integers that are divisible by 2 or 3 is: " << result << endl;
35 | return 0;
36 | }
37 |
--------------------------------------------------------------------------------
/java/src/demo08_return_value/AppB.java:
--------------------------------------------------------------------------------
1 | /*
2 | * GETTING RETURNED VALUES FROM THREADS
3 | */
4 |
5 | package demo08_return_value;
6 |
7 |
8 |
9 | public class AppB {
10 |
11 | public static void main(String[] args) throws InterruptedException {
12 | int[] result = new int[2];
13 |
14 | var thFoo = new Thread(() -> result[0] = doubleValue(5));
15 | var thBar = new Thread(() -> result[1] = doubleValue(80));
16 |
17 | thFoo.start();
18 | thBar.start();
19 |
20 | // Wait until thFoo and thBar finish
21 | thFoo.join();
22 | thBar.join();
23 |
24 | System.out.println(result[0]);
25 | System.out.println(result[1]);
26 | }
27 |
28 |
29 | private static int doubleValue(int value) {
30 | return value * 2;
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/java/src/demo10_yield/App.java:
--------------------------------------------------------------------------------
1 | /*
2 | * THREAD YIELDING
3 | */
4 |
5 | package demo10_yield;
6 |
7 | import java.time.Duration;
8 | import java.time.Instant;
9 |
10 |
11 |
12 | public class App {
13 |
14 | public static void main(String[] args) {
15 | var tpStartMeasure = Instant.now();
16 |
17 | littleSleep(130000);
18 |
19 | var timeElapsed = Duration.between(tpStartMeasure, Instant.now());
20 |
21 | System.out.println("Elapsed time: " + timeElapsed.toNanos() + " nanoseonds");
22 | }
23 |
24 |
25 | private static void littleSleep(int ns) {
26 | var tpStart = Instant.now();
27 | var tpEnd = tpStart.plusNanos(ns);
28 |
29 | do {
30 | Thread.yield();
31 | }
32 | while (Instant.now().isBefore(tpEnd));
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/cpp/cpp-std/demo06b-list-threads.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | LIST OF MULTIPLE THREADS
3 | Version B: Using the std::vector
4 | */
5 |
6 |
7 | #include
8 | #include
9 | #include
10 | using namespace std;
11 |
12 |
13 |
14 | void doTask(int index) {
15 | cout << index;
16 | }
17 |
18 |
19 |
20 | int main() {
21 | constexpr int NUM_THREADS = 5;
22 |
23 | vector lstTh;
24 |
25 | for (int i = 0; i < NUM_THREADS; ++i) {
26 | lstTh.push_back(std::thread(&doTask, i));
27 |
28 | // or...
29 | // auto th = std::thread(&doTask, i);
30 | // lstTh.push_back(std::move(th)); // Because std::thread does not have copy constructors
31 | }
32 |
33 | for (auto&& th : lstTh) {
34 | th.join();
35 | }
36 |
37 | cout << endl;
38 | return 0;
39 | }
40 |
--------------------------------------------------------------------------------
/old/cppstd-reentrant-lock-a.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | REENTRANT LOCK (RECURSIVE MUTEX)
3 |
4 | The function "getFactorial" will cause deadlock.
5 | */
6 |
7 |
8 | #include
9 | #include
10 | #include
11 | using namespace std;
12 |
13 |
14 |
15 | std::mutex mut;
16 |
17 |
18 |
19 | int getFactorial(int n) {
20 | if (n <= 0)
21 | return 1;
22 |
23 | mut.lock();
24 |
25 | int result = n * getFactorial(n - 1);
26 |
27 | mut.unlock();
28 |
29 | return result;
30 | }
31 |
32 |
33 |
34 | void routine(int n) {
35 | int factorial = getFactorial(n);
36 | cout << "Factorial of " << n << " is " << factorial << endl;
37 | }
38 |
39 |
40 |
41 | int main() {
42 | int n = 5;
43 |
44 | auto th = std::thread(routine, n);
45 |
46 | th.join();
47 |
48 | return 0;
49 | }
50 |
--------------------------------------------------------------------------------
/cpp/cpp-pthread/demo08b-return-value.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | GETTING RETURNED VALUES FROM THREADS
3 | Version B: Values returned via pthread_exit
4 | */
5 |
6 |
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | void* doubleValue(void* arg) {
14 | auto value = *(int*) arg;
15 |
16 | int *result = new int;
17 | *result = value * 2;
18 |
19 | pthread_exit((void*)result);
20 | return (void*)result;
21 | }
22 |
23 |
24 |
25 | int main() {
26 | pthread_t tid;
27 | int arg = 80;
28 | int *result = nullptr;
29 | int ret = 0;
30 |
31 | ret = pthread_create(&tid, nullptr, &doubleValue, &arg);
32 | ret = pthread_join(tid, (void**)&result);
33 |
34 | cout << (*result) << endl;
35 |
36 | delete result;
37 | result = nullptr;
38 |
39 | return 0;
40 | }
41 |
--------------------------------------------------------------------------------
/csharp/demoex/demoex-async-future-c02.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * ASYNCHRONOUS PROGRAMMING WITH THE FUTURE/TASK
3 | */
4 | using System;
5 | using System.Threading.Tasks;
6 |
7 |
8 |
9 | class DemoExAsyncC02 : IRunnable
10 | {
11 | public void run()
12 | {
13 | var task = getSquared(7)
14 | .ContinueWith((previousTask) => getDiv2(previousTask.Result))
15 | .Unwrap()
16 | .ContinueWith((previousTask) => Console.WriteLine(previousTask.Result));
17 |
18 | task.Wait();
19 | }
20 |
21 | private async Task getSquared(int x)
22 | {
23 | await Task.Delay(100);
24 | return x * x;
25 | }
26 |
27 | private async Task getDiv2(int x)
28 | {
29 | await Task.Delay(100);
30 | return x / 2;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/csharp/demo/demo12b01-data-race-single.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * DATA RACES
3 | * Version 01: Without multithreading
4 | */
5 | using System;
6 | using System.Linq;
7 |
8 |
9 |
10 | class Demo12B01 : IRunnable
11 | {
12 | public void run()
13 | {
14 | const int N = 8;
15 | int result = getResult(N);
16 | Console.WriteLine("Numbers of integers that are divisible by 2 or 3 is: " + result);
17 | }
18 |
19 |
20 | private int getResult(int N)
21 | {
22 | var a = Enumerable.Repeat(false, N + 1).ToArray();
23 |
24 | for (int i = 1; i <= N; ++i)
25 | if (i % 2 == 0 || i % 3 == 0)
26 | a[i] = true;
27 |
28 | // res = number of true values in array
29 | int res = a.Count(val => val);
30 | return res;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/cpp/cpp-boost/demo06b-list-threads.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | LIST OF MULTIPLE THREADS
3 | Version B: Using the std::vector
4 | */
5 |
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | using namespace std;
12 |
13 |
14 |
15 | typedef boost::shared_ptr threadptr;
16 |
17 |
18 |
19 | void doTask(int index) {
20 | cout << index;
21 | }
22 |
23 |
24 |
25 | int main() {
26 | const int NUM_THREADS = 5;
27 |
28 | vector lstTh;
29 |
30 | for (int i = 0; i < NUM_THREADS; ++i) {
31 | threadptr ptr = boost::make_shared(&doTask, i);
32 | lstTh.push_back(ptr);
33 | }
34 |
35 | for (int i = 0; i < lstTh.size(); ++i) {
36 | lstTh[i]->join();
37 | }
38 |
39 | cout << endl;
40 | return 0;
41 | }
42 |
--------------------------------------------------------------------------------
/cpp/cpp-boost/demo21a01-condition-variable.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | CONDITION VARIABLES
3 | */
4 |
5 |
6 | #include
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | boost::mutex mut;
14 | boost::condition_variable conditionVar;
15 |
16 |
17 |
18 | void foo() {
19 | cout << "foo is waiting..." << endl;
20 |
21 | boost::unique_lock mutLock(mut);
22 | conditionVar.wait(mutLock);
23 |
24 | cout << "foo resumed" << endl;
25 | }
26 |
27 |
28 |
29 | void bar() {
30 | boost::this_thread::sleep_for(boost::chrono::seconds(3));
31 | conditionVar.notify_one();
32 | }
33 |
34 |
35 |
36 | int main() {
37 | boost::thread thFoo(&foo);
38 | boost::thread thBar(&bar);
39 |
40 | thFoo.join();
41 | thBar.join();
42 |
43 | return 0;
44 | }
45 |
--------------------------------------------------------------------------------
/cpp/cpp-pthread/demo25a-atomic.c:
--------------------------------------------------------------------------------
1 | /*
2 | ATOMIC ACCESS
3 |
4 | In this demo, I use raw C language (not C++).
5 | */
6 |
7 |
8 | #include
9 | #include
10 | #include
11 |
12 |
13 |
14 | volatile int counter;
15 |
16 |
17 |
18 | void* doTask(void* arg) {
19 | sleep(1);
20 | counter += 1;
21 |
22 | pthread_exit(NULL);
23 | return NULL;
24 | }
25 |
26 |
27 |
28 | int main() {
29 | counter = 0;
30 |
31 | pthread_t lstTid[1000];
32 | int ret = 0;
33 |
34 | for (int i = 0; i < 1000; ++i) {
35 | ret = pthread_create(&lstTid[i], NULL, &doTask, NULL);
36 | }
37 |
38 | for (int i = 0; i < 1000; ++i) {
39 | ret = pthread_join(lstTid[i], NULL);
40 | }
41 |
42 | // Unpredictable result
43 | printf("counter = %d \n", counter);
44 | return 0;
45 | }
46 |
--------------------------------------------------------------------------------
/python/demo15b_deadlock.py:
--------------------------------------------------------------------------------
1 | '''
2 | DEADLOCK
3 | Version B
4 | '''
5 |
6 | import time
7 | import threading
8 |
9 |
10 |
11 | mutex_a = threading.Lock()
12 | mutex_b = threading.Lock()
13 |
14 |
15 |
16 | def foo():
17 | with mutex_a:
18 | print('foo acquired resource A')
19 | time.sleep(1)
20 | with mutex_b:
21 | print('foo acquired resource B')
22 |
23 |
24 |
25 | def bar():
26 | with mutex_b:
27 | print('bar acquired resource B')
28 | time.sleep(1)
29 | with mutex_a:
30 | print('bar acquired resource A')
31 |
32 |
33 |
34 | th_foo = threading.Thread(target=foo)
35 | th_bar = threading.Thread(target=bar)
36 |
37 | th_foo.start()
38 | th_bar.start()
39 | th_foo.join()
40 | th_bar.join()
41 |
42 | print('You will never see this statement due to deadlock!')
43 |
--------------------------------------------------------------------------------
/cpp/cpp-std/demo10-yield.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | THREAD YIELDING
3 | */
4 |
5 |
6 | #include
7 | #include
8 | #include
9 | #include "mylib-time.hpp"
10 | using namespace std;
11 |
12 |
13 |
14 | using chrmicro = std::chrono::microseconds;
15 | using hrclock = mylib::HiResClock;
16 |
17 |
18 |
19 | void littleSleep(int us) {
20 | auto tpStart = hrclock::now();
21 | auto tpEnd = tpStart + chrmicro(us);
22 |
23 | do {
24 | std::this_thread::yield();
25 | }
26 | while (hrclock::now() < tpEnd);
27 | }
28 |
29 |
30 |
31 | int main() {
32 | auto tpStartMeasure = hrclock::now();
33 |
34 | littleSleep(130);
35 |
36 | auto timeElapsed = hrclock::getTimeSpan(tpStartMeasure);
37 |
38 | cout << "Elapsed time: " << timeElapsed.count() << " microseonds" << endl;
39 | return 0;
40 | }
41 |
--------------------------------------------------------------------------------
/cpp/cpp-std/demo12c01-race-cond-data-race.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | RACE CONDITIONS AND DATA RACES
3 | */
4 |
5 |
6 | #include
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | int counter = 0;
14 |
15 |
16 |
17 | void increaseCounter() {
18 | std::this_thread::sleep_for(std::chrono::seconds(1));
19 |
20 | for (int i = 0; i < 1000; ++i) {
21 | counter += 1;
22 | }
23 | }
24 |
25 |
26 |
27 | int main() {
28 | constexpr int NUM_THREADS = 16;
29 | std::thread lstTh[NUM_THREADS];
30 |
31 | for (auto&& th : lstTh) {
32 | th = std::thread(&increaseCounter);
33 | }
34 |
35 | for (auto&& th : lstTh) {
36 | th.join();
37 | }
38 |
39 | cout << "counter = " << counter << endl;
40 | // We are NOT sure that counter = 16000
41 |
42 | return 0;
43 | }
44 |
--------------------------------------------------------------------------------
/java/src/demo07_terminate/AppA.java:
--------------------------------------------------------------------------------
1 | /*
2 | * FORCING A THREAD TO TERMINATE (i.e. killing the thread)
3 | * Version A: Interrupting the thread
4 | */
5 |
6 | package demo07_terminate;
7 |
8 |
9 |
10 | public class AppA {
11 |
12 | public static void main(String[] args) throws InterruptedException {
13 | var th = new Thread(() -> {
14 | while (true) {
15 | System.out.println("Running...");
16 |
17 | try { Thread.sleep(1000); }
18 | catch (InterruptedException e) {
19 | // Received interrupt signal, now current thread is going to exit
20 | return;
21 | }
22 | }
23 | });
24 |
25 |
26 | th.start();
27 |
28 | Thread.sleep(3000);
29 |
30 | th.interrupt();
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/cpp/cpp-boost/demo12c01-race-cond-data-race.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | RACE CONDITIONS AND DATA RACES
3 | */
4 |
5 |
6 | #include
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | int counter = 0;
14 |
15 |
16 |
17 | void increaseCounter() {
18 | boost::this_thread::sleep_for(boost::chrono::seconds(1));
19 |
20 | for (int i = 0; i < 1000; ++i) {
21 | counter += 1;
22 | }
23 | }
24 |
25 |
26 |
27 | int main() {
28 | const int NUM_THREADS = 16;
29 | boost::thread_group lstTh;
30 |
31 | for (int i = 0; i < NUM_THREADS; ++i) {
32 | lstTh.add_thread(new boost::thread(&increaseCounter));
33 | }
34 |
35 | lstTh.join_all();
36 |
37 | cout << "counter = " << counter << endl;
38 | // We are NOT sure that counter = 16000
39 |
40 | return 0;
41 | }
42 |
--------------------------------------------------------------------------------
/cpp/cpp-boost/demo13a-mutex.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | MUTEXES
3 | */
4 |
5 |
6 | #include
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | boost::mutex mut;
14 | int counter = 0;
15 |
16 |
17 |
18 | void doTask() {
19 | boost::this_thread::sleep_for(boost::chrono::seconds(1));
20 |
21 | mut.lock();
22 |
23 | for (int i = 0; i < 1000; ++i)
24 | ++counter;
25 |
26 | mut.unlock();
27 | }
28 |
29 |
30 |
31 | int main() {
32 | const int NUM_THREADS = 16;
33 | boost::thread_group lstTh;
34 |
35 | for (int i = 0; i < NUM_THREADS; ++i) {
36 | lstTh.add_thread(new boost::thread(&doTask));
37 | }
38 |
39 | lstTh.join_all();
40 |
41 | cout << "counter = " << counter << endl;
42 | // We are sure that counter = 16000
43 |
44 | return 0;
45 | }
46 |
--------------------------------------------------------------------------------
/cpp/cpp-pthread/demo12b01-data-race-single.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | DATA RACES
3 | Version 01: Without multithreading
4 | */
5 |
6 |
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | int *a = nullptr;
14 | int N = 0;
15 |
16 |
17 |
18 | int getResult() {
19 | a = (int*)calloc(sizeof(int), N + 1);
20 |
21 | for (int i = 1; i <= N; ++i)
22 | if (0 == i % 2 || 0 == i % 3)
23 | a[i] = 1;
24 |
25 | int result = 0;
26 |
27 | for (int i = 1; i <= N; ++i)
28 | if (a[i])
29 | ++result;
30 |
31 | free(a);
32 | a = nullptr;
33 |
34 | return result;
35 | }
36 |
37 |
38 |
39 | int main() {
40 | N = 8;
41 |
42 | int result = getResult();
43 |
44 | cout << "Numbers of integers that are divisible by 2 or 3 is: " << result << endl;
45 | return 0;
46 | }
47 |
--------------------------------------------------------------------------------
/java/src/demoex/async/AppC02.java:
--------------------------------------------------------------------------------
1 | /*
2 | * ASYNCHRONOUS PROGRAMMING WITH THE FUTURE/TASK
3 | */
4 |
5 | package demoex.async;
6 |
7 | import java.util.concurrent.CompletableFuture;
8 | import java.util.concurrent.ExecutionException;
9 |
10 |
11 |
12 | public class AppC02 {
13 |
14 | public static void main(String[] args) throws InterruptedException, ExecutionException {
15 | CompletableFuture task;
16 |
17 | task = CompletableFuture
18 | .supplyAsync(() -> getSquared(7))
19 | .thenApply(AppC02::getDiv2)
20 | .thenAccept(System.out::println);
21 |
22 | task.get();
23 | }
24 |
25 |
26 | private static int getSquared(int x) {
27 | return x * x;
28 | }
29 |
30 |
31 | private static int getDiv2(int x) {
32 | return x / 2;
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/cpp/cpp-pthread/demoex-signal.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | using namespace std;
6 |
7 |
8 |
9 | void signalHandler(int sig) {
10 | cout << "caught signal " << sig << endl;
11 | // signal(SIGSEGV, signalHandler);
12 | }
13 |
14 |
15 |
16 | void* func(void* arg) {
17 | cout << "foo" << endl;
18 | sleep(5);
19 |
20 | pthread_exit(nullptr);
21 | return nullptr;
22 | }
23 |
24 |
25 |
26 | int main() {
27 | pthread_t tid;
28 |
29 | signal(SIGSEGV, signalHandler); // Register signal handler before going multithread
30 |
31 | pthread_create(&tid, nullptr, &func, nullptr);
32 | sleep(1); // Leave time for initialization
33 |
34 | pthread_kill(tid, SIGSEGV);
35 |
36 | pthread_join(tid, NULL);
37 |
38 | cout << "bar" << endl;
39 | return 0;
40 | }
41 |
--------------------------------------------------------------------------------
/cpp/cpp-pthread/demo08a-return-value.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | GETTING RETURNED VALUES FROM THREADS
3 | Version A: Values returned via pointers passed from arguments
4 | */
5 |
6 |
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | struct ThreadArg {
14 | int value;
15 | int *res;
16 | };
17 |
18 |
19 |
20 | void* doubleValue(void* argVoid) {
21 | auto arg = (ThreadArg*) argVoid;
22 |
23 | *(arg->res) = arg->value * 2;
24 |
25 | pthread_exit(nullptr);
26 | return nullptr;
27 | }
28 |
29 |
30 |
31 | int main() {
32 | pthread_t tid;
33 | int result;
34 | ThreadArg arg;
35 | int ret = 0;
36 |
37 | arg = { 80, &result };
38 |
39 | ret = pthread_create(&tid, nullptr, &doubleValue, &arg);
40 | ret = pthread_join(tid, nullptr);
41 |
42 | cout << result << endl;
43 | return 0;
44 | }
45 |
--------------------------------------------------------------------------------
/cpp/cpp-std/demo13a-mutex.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | MUTEXES
3 | */
4 |
5 |
6 | #include
7 | #include
8 | #include
9 | #include
10 | using namespace std;
11 |
12 |
13 |
14 | std::mutex mut;
15 | int counter = 0;
16 |
17 |
18 |
19 | void doTask() {
20 | std::this_thread::sleep_for(std::chrono::seconds(1));
21 |
22 | mut.lock();
23 |
24 | for (int i = 0; i < 1000; ++i)
25 | ++counter;
26 |
27 | mut.unlock();
28 | }
29 |
30 |
31 |
32 | int main() {
33 | constexpr int NUM_THREADS = 16;
34 | std::thread lstTh[NUM_THREADS];
35 |
36 | for (auto&& th : lstTh) {
37 | th = std::thread(&doTask);
38 | }
39 |
40 | for (auto&& th : lstTh) {
41 | th.join();
42 | }
43 |
44 | cout << "counter = " << counter << endl;
45 | // We are sure that counter = 16000
46 |
47 | return 0;
48 | }
49 |
--------------------------------------------------------------------------------
/cpp/cpp-std/demo21a01-condition-variable.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | CONDITION VARIABLES
3 | */
4 |
5 |
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | using namespace std;
12 |
13 |
14 |
15 | std::mutex mut;
16 | std::condition_variable conditionVar;
17 |
18 |
19 |
20 | void foo() {
21 | cout << "foo is waiting..." << endl;
22 |
23 | std::unique_lock mutLock(mut);
24 | conditionVar.wait(mutLock);
25 |
26 | cout << "foo resumed" << endl;
27 | }
28 |
29 |
30 |
31 | void bar() {
32 | std::this_thread::sleep_for(std::chrono::seconds(3));
33 | conditionVar.notify_one();
34 | }
35 |
36 |
37 |
38 | int main() {
39 | auto thFoo = std::thread(&foo);
40 | auto thBar = std::thread(&bar);
41 |
42 | thFoo.join();
43 | thBar.join();
44 |
45 | return 0;
46 | }
47 |
--------------------------------------------------------------------------------
/python/demo20a02_semaphore.py:
--------------------------------------------------------------------------------
1 | '''
2 | SEMAPHORES
3 | Version A: Paper sheets and packages
4 | '''
5 |
6 | import time
7 | import threading
8 |
9 |
10 |
11 | sem_package = threading.Semaphore(0)
12 | sem_sheet = threading.Semaphore(2)
13 |
14 |
15 |
16 | def make_one_sheet():
17 | for _ in range(4):
18 | sem_sheet.acquire()
19 | print('Make 1 sheet')
20 | sem_package.release()
21 |
22 |
23 |
24 | def combine_one_package():
25 | for _ in range(4):
26 | sem_package.acquire()
27 | sem_package.acquire()
28 | print('Combine 2 sheets into 1 package')
29 | time.sleep(2)
30 | sem_sheet.release()
31 | sem_sheet.release()
32 |
33 |
34 |
35 | threading.Thread(target=make_one_sheet).start()
36 | threading.Thread(target=make_one_sheet).start()
37 | threading.Thread(target=combine_one_package).start()
38 |
--------------------------------------------------------------------------------
/python/demo22b_blocking_queue.py:
--------------------------------------------------------------------------------
1 | '''
2 | BLOCKING QUEUES
3 | Version B: A fast producer and a slow consumer
4 | '''
5 |
6 | import time
7 | from queue import Queue
8 | import threading
9 |
10 |
11 |
12 | def producer(q: Queue):
13 | q.put('Alice')
14 | q.put('likes')
15 |
16 | # Due to reaching the maximum capacity = 2, when executing q.put('singing'),
17 | # this thread is going to sleep until the queue removes an element.
18 | q.put('singing')
19 |
20 |
21 |
22 | def consumer(q: Queue):
23 | time.sleep(2)
24 |
25 | for _ in range(3):
26 | print('\nWaiting for data...')
27 | data = q.get()
28 | print(f' {data}')
29 |
30 |
31 |
32 | blkq = Queue(maxsize=2) # blocking queue with capacity = 2
33 |
34 | threading.Thread(target=producer, args=(blkq,)).start()
35 | threading.Thread(target=consumer, args=(blkq,)).start()
36 |
--------------------------------------------------------------------------------
/cpp/cpp-pthread/demo06a-list-threads.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | LIST OF MULTIPLE THREADS
3 | Version A: Using standard arrays
4 | */
5 |
6 |
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | void* doTask(void* arg) {
14 | auto index = *(int*) arg;
15 | cout << index;
16 |
17 | pthread_exit(nullptr);
18 | return nullptr;
19 | }
20 |
21 |
22 |
23 | int main() {
24 | constexpr int NUM_THREADS = 5;
25 |
26 | pthread_t lstTid[NUM_THREADS];
27 | int lstArg[NUM_THREADS];
28 |
29 | int ret = 0;
30 |
31 |
32 | for (int i = 0; i < NUM_THREADS; ++i) {
33 | lstArg[i] = i;
34 | ret = pthread_create(&lstTid[i], nullptr, &doTask, &lstArg[i]);
35 | }
36 |
37 | for (auto&& tid : lstTid) {
38 | ret = pthread_join(tid, nullptr);
39 | }
40 |
41 |
42 | cout << endl;
43 | return 0;
44 | }
45 |
--------------------------------------------------------------------------------
/cpp/cpp-pthread/demo12bex-data-race-fork.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | DATA RACES
3 | */
4 |
5 |
6 | #include
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | int main() {
14 | int pid = 0;
15 |
16 | pid = fork();
17 |
18 | if (-1 == pid) {
19 | cerr << "Cannot fork" << endl;
20 | return 1;
21 | }
22 |
23 |
24 | ofstream ofs;
25 | ofs.open("tmp-output.txt");
26 |
27 | if (ofs.fail()) {
28 | return 1;
29 | }
30 |
31 | cout << "Writing to the file..." << endl;
32 |
33 | ofs << pid << endl;
34 |
35 | ofs.close();
36 | return 0;
37 | }
38 |
39 |
40 | /*
41 | The content of the file is UNKNOWN.
42 | It may be:
43 | 0
44 |
45 | or
46 | 34
47 |
48 | or
49 | 0
50 | 34
51 |
52 | or
53 | 34
54 | 0
55 |
56 | Assume that 34 and 0 are process ids.
57 | */
58 |
--------------------------------------------------------------------------------
/cpp/cpp-std/demo08a-return-value.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | GETTING RETURNED VALUES FROM THREADS
3 | Version A: Using pointers or references (traditional way)
4 | */
5 |
6 |
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | void doubleValue(int arg, int* res) {
14 | (*res) = arg * 2;
15 | }
16 |
17 |
18 |
19 | void squareValue(int arg, int& res) {
20 | res = arg * arg;
21 | }
22 |
23 |
24 |
25 | int main() {
26 | int result[3];
27 |
28 | auto thFoo = std::thread(&doubleValue, 5, &result[0]);
29 | auto thBar = std::thread(&doubleValue, 80, &result[1]);
30 | auto thEgg = std::thread(&squareValue, 7, std::ref(result[2]));
31 |
32 | thFoo.join();
33 | thBar.join();
34 | thEgg.join();
35 |
36 | cout << result[0] << endl;
37 | cout << result[1] << endl;
38 | cout << result[2] << endl;
39 |
40 | return 0;
41 | }
42 |
--------------------------------------------------------------------------------
/java/src/demo03_pass_arg/AppA.java:
--------------------------------------------------------------------------------
1 | /*
2 | * PASSING ARGUMENTS
3 | * Version A: Passing arguments to Thread objects
4 | */
5 |
6 | package demo03_pass_arg;
7 |
8 |
9 |
10 | public class AppA {
11 |
12 | public static void main(String[] args) throws InterruptedException {
13 | var thFoo = new MyThread(1, 2, "red");
14 | var thBar = new MyThread(3, 4, "blue");
15 |
16 | thFoo.start();
17 | thBar.start();
18 | }
19 |
20 | }
21 |
22 |
23 |
24 | class MyThread extends Thread {
25 | private int a;
26 | private double b;
27 | private String c;
28 |
29 | public MyThread(int a, double b, String c) {
30 | super();
31 | this.a = a;
32 | this.b = b;
33 | this.c = c;
34 | }
35 |
36 | @Override
37 | public void run() {
38 | System.out.printf("%d %.1f %s %n", a, b, c);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/java/src/demo08_return_value/AppA.java:
--------------------------------------------------------------------------------
1 | /*
2 | * GETTING RETURNED VALUES FROM THREADS
3 | */
4 |
5 | package demo08_return_value;
6 |
7 |
8 |
9 | public class AppA {
10 |
11 | public static void main(String[] args) throws InterruptedException {
12 | var thFoo = new MyThread(5);
13 | var thBar = new MyThread(80);
14 |
15 | thFoo.start();
16 | thBar.start();
17 |
18 | thFoo.join();
19 | thBar.join();
20 |
21 | System.out.println(thFoo.result);
22 | System.out.println(thBar.result);
23 | }
24 |
25 | }
26 |
27 |
28 |
29 | class MyThread extends Thread {
30 | public int arg = 0;
31 | public int result = 0;
32 |
33 | public MyThread(int arg) {
34 | super();
35 | this.arg = arg;
36 | }
37 |
38 | @Override
39 | public void run() {
40 | result = arg * 2;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/cpp/cpp-pthread/demo03a01-pass-arg.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | PASSING ARGUMENTS
3 | Version A01: The problem
4 |
5 | The id in statement "hello pthread with id..." might be DUPLICATED!!!
6 | Reason: Passing the address of variable i,
7 | so that all threads use a same value of i.
8 | */
9 |
10 |
11 | #include
12 | #include
13 | using namespace std;
14 |
15 |
16 |
17 | void* doTask(void* ptrId) {
18 | int id = *(int*)ptrId;
19 |
20 | cout << "Hello pthread with id = " << id << endl;
21 |
22 | pthread_exit(nullptr);
23 | return nullptr;
24 | }
25 |
26 |
27 |
28 | int main() {
29 | pthread_t lstTid[2];
30 | int ret = 0;
31 |
32 | for (int i = 0; i < 2; ++i)
33 | ret = pthread_create(&lstTid[i], nullptr, &doTask, &i);
34 |
35 | for (int i = 0; i < 2; ++i)
36 | ret = pthread_join(lstTid[i], nullptr);
37 |
38 | return 0;
39 | }
40 |
--------------------------------------------------------------------------------
/cpp/cpp-pthread/demo12a-race-condition.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | RACE CONDITIONS
3 | */
4 |
5 |
6 | #include
7 | #include
8 | #include
9 | using namespace std;
10 |
11 |
12 |
13 | void* doTask(void* arg) {
14 | int index = *(int*) arg;
15 |
16 | sleep(1);
17 |
18 | cout << index;
19 |
20 | pthread_exit(nullptr);
21 | return nullptr;
22 | }
23 |
24 |
25 |
26 | int main() {
27 | constexpr int NUM_THREADS = 4;
28 |
29 | pthread_t lstTid[NUM_THREADS];
30 | int lstArg[NUM_THREADS];
31 |
32 | int ret = 0;
33 |
34 |
35 | for (int i = 0; i < NUM_THREADS; ++i) {
36 | lstArg[i] = i;
37 | ret = pthread_create(&lstTid[i], nullptr, &doTask, &lstArg[i]);
38 | }
39 |
40 | for (auto&& tid : lstTid) {
41 | ret = pthread_join(tid, nullptr);
42 | }
43 |
44 |
45 | cout << endl;
46 | return 0;
47 | }
48 |
--------------------------------------------------------------------------------
/cpp/cpp-std/demo03a-pass-arg.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | PASSING ARGUMENTS
3 | Version A: Passing multiple arguments with various data types
4 | */
5 |
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | using namespace std;
12 |
13 |
14 |
15 | struct Point {
16 | int x;
17 | int y;
18 |
19 | Point(int x, int y): x(x), y(y) { }
20 | };
21 |
22 |
23 |
24 | void doTask(int a, double b, string c, char const* d, Point e) {
25 | char buffer[50] = { 0 };
26 | std::sprintf(buffer, "%d %.1f %s %s (%d %d)", a, b, c.data(), d, e.x, e.y);
27 | cout << buffer << endl;
28 | }
29 |
30 |
31 |
32 | int main() {
33 | auto thFoo = std::thread(&doTask, 1, 2, "red", "red", Point(0, 0));
34 | auto thBar = std::thread(&doTask, 3, 4, "blue", "blue", Point(9, 9));
35 |
36 | thFoo.join();
37 | thBar.join();
38 |
39 | return 0;
40 | }
41 |
--------------------------------------------------------------------------------
/csharp/demo/demo17a-reentrant-lock.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * REENTRANT LOCKS (RECURSIVE MUTEXES)
3 | *
4 | * In C#, "lock" keyword and System.Threading.Monitor class allow re-entrancy.
5 | * That means they are reentrant locks by default.
6 | *
7 | * Version A: A simple example
8 | */
9 | using System;
10 | using System.Threading;
11 |
12 |
13 |
14 | class Demo17A : IRunnable
15 | {
16 | public void run()
17 | {
18 | const string resource = "resource";
19 |
20 | new Thread(() =>
21 | {
22 | lock (resource)
23 | {
24 | Console.WriteLine("First time acquiring the resource");
25 |
26 | lock (resource)
27 | {
28 | Console.WriteLine("Second time acquiring the resource");
29 | }
30 | }
31 | }).Start();
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/cpp/cpp-boost/demo03a-pass-arg.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | PASSING ARGUMENTS
3 | Version A: Passing multiple arguments with various data types
4 | */
5 |
6 |
7 | #include
8 | #include
9 | #include