Full Code of thanhit95/multi-threading for AI

main 9557cdf0f2a6 cached
672 files
824.3 KB
225.7k tokens
2095 symbols
1 requests
Download .txt
Showing preview only (971K chars total). Download the full file or copy to clipboard to get everything.
Repository: thanhit95/multi-threading
Branch: main
Commit: 9557cdf0f2a6
Files: 672
Total size: 824.3 KB

Directory structure:
gitextract_mqx2volu/

├── .gitignore
├── LICENSE.txt
├── README.md
├── cpp/
│   ├── .gitignore
│   ├── README.md
│   ├── cpp-boost/
│   │   ├── demo00.cpp
│   │   ├── demo01a01-hello.cpp
│   │   ├── demo01a02-hello.cpp
│   │   ├── demo01b-hello-class01.cpp
│   │   ├── demo01b-hello-class02.cpp
│   │   ├── demo01b-hello-class03.cpp
│   │   ├── demo01b-hello-functor.cpp
│   │   ├── demo02-join.cpp
│   │   ├── demo03a-pass-arg.cpp
│   │   ├── demo03b-pass-arg.cpp
│   │   ├── demo03c-pass-arg.cpp
│   │   ├── demo04a-sleep.cpp
│   │   ├── demo04b-sleep.cpp
│   │   ├── demo05-id.cpp
│   │   ├── demo06a-list-threads.cpp
│   │   ├── demo06b-list-threads.cpp
│   │   ├── demo06c-list-threads.cpp
│   │   ├── demo07-terminate.cpp
│   │   ├── demo08-return-value.cpp
│   │   ├── demo09-detach.cpp
│   │   ├── demo10-yield.cpp
│   │   ├── demo11a-exec-service.cpp
│   │   ├── demo11b-exec-service.cpp
│   │   ├── demo12a-race-condition.cpp
│   │   ├── demo12b01-data-race-single.cpp
│   │   ├── demo12b02-data-race-multi.cpp
│   │   ├── demo12c01-race-cond-data-race.cpp
│   │   ├── demo12c02-race-cond-data-race.cpp
│   │   ├── demo13a-mutex.cpp
│   │   ├── demo13b01-mutex.cpp
│   │   ├── demo13b02-mutex.cpp
│   │   ├── demo13c-mutex-trylock.cpp
│   │   ├── demo14-synchronized-block.cpp
│   │   ├── demo15a-deadlock.cpp
│   │   ├── demo15b-deadlock.cpp
│   │   ├── demo16-monitor.cpp
│   │   ├── demo17a-reentrant-lock.cpp
│   │   ├── demo17b-reentrant-lock.cpp
│   │   ├── demo17c-reentrant-lock.cpp
│   │   ├── demo18a01-barrier.cpp
│   │   ├── demo18a02-barrier.cpp
│   │   ├── demo18a03-barrier.cpp
│   │   ├── demo18b01-latch.cpp
│   │   ├── demo18b02-latch.cpp
│   │   ├── demo19a-read-write-lock.cpp
│   │   ├── demo19b-read-write-lock.cpp
│   │   ├── demo20a01-semaphore.cpp
│   │   ├── demo20a02-semaphore.cpp
│   │   ├── demo20a03-semaphore-deadlock.cpp
│   │   ├── demo20b-semaphore.cpp
│   │   ├── demo21a01-condition-variable.cpp
│   │   ├── demo21a02-condition-variable.cpp
│   │   ├── demo21a03-condition-variable.cpp
│   │   ├── demo21b-condition-variable.cpp
│   │   ├── demo22a-blocking-queue.cpp
│   │   ├── demo22b-blocking-queue.cpp
│   │   ├── demo23a-thread-local.cpp
│   │   ├── demo23b-thread-local.cpp
│   │   ├── demo24-volatile.cpp
│   │   ├── demo25a-atomic.cpp
│   │   ├── demo25b-atomic.cpp
│   │   ├── demoex-async-future.cpp
│   │   ├── exer01a-max-div.cpp
│   │   ├── exer01b-max-div.cpp
│   │   ├── exer01c-max-div.cpp
│   │   ├── exer02a01-producer-consumer.cpp
│   │   ├── exer02a02-producer-consumer.cpp
│   │   ├── exer02a03-producer-consumer.cpp
│   │   ├── exer02a04-producer-consumer.cpp
│   │   ├── exer02b01-producer-consumer.cpp
│   │   ├── exer02b02-producer-consumer.cpp
│   │   ├── exer02b03-producer-consumer.cpp
│   │   ├── exer02b04-producer-consumer.cpp
│   │   ├── exer02c-producer-consumer.cpp
│   │   ├── exer03a-readers-writers.cpp
│   │   ├── exer03b-readers-writers.cpp
│   │   ├── exer04-dining-philosophers.cpp
│   │   ├── exer05-util.hpp
│   │   ├── exer05a-product-matrix-vector.cpp
│   │   ├── exer05b-product-matrix-matrix.cpp
│   │   ├── exer06a-blocking-queue.cpp
│   │   ├── exer06b01-blocking-queue.cpp
│   │   ├── exer06b02-blocking-queue.cpp
│   │   ├── exer07a-data-server.cpp
│   │   ├── exer07b-data-server.cpp
│   │   ├── exer07c-data-server.cpp
│   │   ├── exer07d-data-server.cpp
│   │   ├── exer08-exec-service-itask.hpp
│   │   ├── exer08-exec-service-main.cpp
│   │   ├── exer08-exec-service-v0a.hpp
│   │   ├── exer08-exec-service-v0b.hpp
│   │   ├── exer08-exec-service-v1a.hpp
│   │   ├── exer08-exec-service-v1b.hpp
│   │   ├── exer08-exec-service-v2a.hpp
│   │   ├── exer08-exec-service-v2b.hpp
│   │   ├── mylib-blockingqueue.hpp
│   │   ├── mylib-random.hpp
│   │   ├── mylib-semaphore.hpp
│   │   └── mylib-time.hpp
│   ├── cpp-pthread/
│   │   ├── demo00.cpp
│   │   ├── demo01-hello.cpp
│   │   ├── demo02-join.cpp
│   │   ├── demo03a01-pass-arg.cpp
│   │   ├── demo03a02-pass-arg.cpp
│   │   ├── demo03b01-pass-arg.cpp
│   │   ├── demo03b02-pass-arg.cpp
│   │   ├── demo04-sleep.cpp
│   │   ├── demo05-id.cpp
│   │   ├── demo06a-list-threads.cpp
│   │   ├── demo06b-list-threads.cpp
│   │   ├── demo07a-terminate.cpp
│   │   ├── demo07b-terminate.cpp
│   │   ├── demo08a-return-value.cpp
│   │   ├── demo08b-return-value.cpp
│   │   ├── demo09a-detach.cpp
│   │   ├── demo09b-detach.cpp
│   │   ├── demo10-yield.cpp
│   │   ├── demo11a-exec-service.cpp
│   │   ├── demo11b-exec-service.cpp
│   │   ├── demo12a-race-condition.cpp
│   │   ├── demo12b01-data-race-single.cpp
│   │   ├── demo12b02-data-race-multi.cpp
│   │   ├── demo12bex-data-race-fork.cpp
│   │   ├── demo12c01-race-cond-data-race.cpp
│   │   ├── demo12c02-race-cond-data-race.cpp
│   │   ├── demo13a-mutex.cpp
│   │   ├── demo13b-mutex-trylock.cpp
│   │   ├── demo14-synchronized-block.cpp
│   │   ├── demo15a-deadlock.cpp
│   │   ├── demo15b-deadlock.cpp
│   │   ├── demo16-monitor.cpp
│   │   ├── demo17a-reentrant-lock.cpp
│   │   ├── demo17b-reentrant-lock.cpp
│   │   ├── demo17c-reentrant-lock.cpp
│   │   ├── demo18a01-barrier.cpp
│   │   ├── demo18a02-barrier.cpp
│   │   ├── demo18a03-barrier.cpp
│   │   ├── demo18b01-latch.cpp
│   │   ├── demo18b02-latch.cpp
│   │   ├── demo19-read-write-lock.cpp
│   │   ├── demo20a01-semaphore.cpp
│   │   ├── demo20a02-semaphore.cpp
│   │   ├── demo20a03-semaphore-deadlock.cpp
│   │   ├── demo20b-semaphore.cpp
│   │   ├── demo21a01-condition-variable.cpp
│   │   ├── demo21a02-condition-variable.cpp
│   │   ├── demo21a03-condition-variable.cpp
│   │   ├── demo21b-condition-variable.cpp
│   │   ├── demo22a-blocking-queue.cpp
│   │   ├── demo22b-blocking-queue.cpp
│   │   ├── demo23a-thread-local.cpp
│   │   ├── demo23b-thread-local.cpp
│   │   ├── demo24-volatile.cpp
│   │   ├── demo25a-atomic.c
│   │   ├── demo25b-atomic.c
│   │   ├── demoex-attribute.cpp
│   │   ├── demoex-oop.cpp
│   │   ├── demoex-signal.cpp
│   │   ├── exer01a-max-div.cpp
│   │   ├── exer01b-max-div.cpp
│   │   ├── exer01c-max-div.cpp
│   │   ├── exer02a01-producer-consumer.cpp
│   │   ├── exer02a02-producer-consumer.cpp
│   │   ├── exer02a03-producer-consumer.cpp
│   │   ├── exer02a04-producer-consumer.cpp
│   │   ├── exer02b01-producer-consumer.cpp
│   │   ├── exer02b02-producer-consumer.cpp
│   │   ├── exer02b03-producer-consumer.cpp
│   │   ├── exer02b04-producer-consumer.cpp
│   │   ├── exer02c-producer-consumer.cpp
│   │   ├── exer03a-readers-writers.cpp
│   │   ├── exer03b-readers-writers.cpp
│   │   ├── exer04-dining-philosophers.cpp
│   │   ├── exer05-util.hpp
│   │   ├── exer05a-product-matrix-vector.cpp
│   │   ├── exer05b-product-matrix-matrix.cpp
│   │   ├── exer06a-blocking-queue.cpp
│   │   ├── exer06b01-blocking-queue.cpp
│   │   ├── exer06b02-blocking-queue.cpp
│   │   ├── exer07a-data-server.cpp
│   │   ├── exer07b-data-server.cpp
│   │   ├── exer07c-data-server.cpp
│   │   ├── exer07d-data-server.cpp
│   │   ├── exer08-exec-service-itask.hpp
│   │   ├── exer08-exec-service-main.cpp
│   │   ├── exer08-exec-service-v0a.hpp
│   │   ├── exer08-exec-service-v0b.hpp
│   │   ├── exer08-exec-service-v1a.hpp
│   │   ├── exer08-exec-service-v1b.hpp
│   │   ├── exer08-exec-service-v2a.hpp
│   │   ├── exer08-exec-service-v2b.hpp
│   │   ├── exerex-countdown-timer-a.cpp
│   │   ├── exerex-countdown-timer-b.cpp
│   │   ├── mylib-blockingqueue.hpp
│   │   ├── mylib-execservice.hpp
│   │   └── mylib-latch.hpp
│   └── cpp-std/
│       ├── demo00.cpp
│       ├── demo01a01-hello.cpp
│       ├── demo01a02-hello.cpp
│       ├── demo01b-hello-class01.cpp
│       ├── demo01b-hello-class02.cpp
│       ├── demo01b-hello-class03.cpp
│       ├── demo01b-hello-functor.cpp
│       ├── demo01c-hello-lambda.cpp
│       ├── demo02-join.cpp
│       ├── demo03a-pass-arg.cpp
│       ├── demo03b-pass-arg.cpp
│       ├── demo03c-pass-arg.cpp
│       ├── demo04a-sleep.cpp
│       ├── demo04b-sleep.cpp
│       ├── demo05-id.cpp
│       ├── demo06a-list-threads.cpp
│       ├── demo06b-list-threads.cpp
│       ├── demo07-terminate.cpp
│       ├── demo08a-return-value.cpp
│       ├── demo08b-return-value.cpp
│       ├── demo08c-return-value.cpp
│       ├── demo09-detach.cpp
│       ├── demo10-yield.cpp
│       ├── demo11a-exec-service.cpp
│       ├── demo11b-exec-service.cpp
│       ├── demo12a-race-condition.cpp
│       ├── demo12b01-data-race-single.cpp
│       ├── demo12b02-data-race-multi.cpp
│       ├── demo12c01-race-cond-data-race.cpp
│       ├── demo12c02-race-cond-data-race.cpp
│       ├── demo13a-mutex.cpp
│       ├── demo13b01-mutex.cpp
│       ├── demo13b02-mutex.cpp
│       ├── demo13c-mutex-trylock.cpp
│       ├── demo14-synchronized-block.cpp
│       ├── demo15a-deadlock.cpp
│       ├── demo15b-deadlock.cpp
│       ├── demo16-monitor.cpp
│       ├── demo17a-reentrant-lock.cpp
│       ├── demo17b-reentrant-lock.cpp
│       ├── demo17c-reentrant-lock.cpp
│       ├── demo18a01-barrier.cpp
│       ├── demo18a02-barrier.cpp
│       ├── demo18a03-barrier.cpp
│       ├── demo18b01-latch.cpp
│       ├── demo18b02-latch.cpp
│       ├── demo19a-read-write-lock.cpp
│       ├── demo19b-read-write-lock.cpp
│       ├── demo20a01-semaphore.cpp
│       ├── demo20a02-semaphore.cpp
│       ├── demo20a03-semaphore-deadlock.cpp
│       ├── demo20b-semaphore.cpp
│       ├── demo21a01-condition-variable.cpp
│       ├── demo21a02-condition-variable.cpp
│       ├── demo21a03-condition-variable.cpp
│       ├── demo21b-condition-variable.cpp
│       ├── demo22a-blocking-queue.cpp
│       ├── demo22b-blocking-queue.cpp
│       ├── demo23a01-thread-local.cpp
│       ├── demo23a02-thread-local.cpp
│       ├── demo23b-thread-local.cpp
│       ├── demo24-volatile.cpp
│       ├── demo25a-atomic.cpp
│       ├── demo25b-atomic.cpp
│       ├── demo25c-atomic-gcc.cpp
│       ├── demoex-async-future.cpp
│       ├── demoex-jthread.cpp
│       ├── exer01a-max-div.cpp
│       ├── exer01b-max-div.cpp
│       ├── exer01c-max-div.cpp
│       ├── exer02a01-producer-consumer.cpp
│       ├── exer02a02-producer-consumer.cpp
│       ├── exer02a03-producer-consumer.cpp
│       ├── exer02a04-producer-consumer.cpp
│       ├── exer02b01-producer-consumer.cpp
│       ├── exer02b02-producer-consumer.cpp
│       ├── exer02b03-producer-consumer.cpp
│       ├── exer02b04-producer-consumer.cpp
│       ├── exer02c-producer-consumer.cpp
│       ├── exer03a-readers-writers.cpp
│       ├── exer03b-readers-writers.cpp
│       ├── exer04-dining-philosophers.cpp
│       ├── exer05-util.hpp
│       ├── exer05a-product-matrix-vector.cpp
│       ├── exer05b-product-matrix-matrix.cpp
│       ├── exer06a-blocking-queue.cpp
│       ├── exer06b01-blocking-queue.cpp
│       ├── exer06b02-blocking-queue.cpp
│       ├── exer07a-data-server.cpp
│       ├── exer07b-data-server.cpp
│       ├── exer07c-data-server.cpp
│       ├── exer07d-data-server.cpp
│       ├── exer08-exec-service-itask.hpp
│       ├── exer08-exec-service-main.cpp
│       ├── exer08-exec-service-v0a.hpp
│       ├── exer08-exec-service-v0b.hpp
│       ├── exer08-exec-service-v1a.hpp
│       ├── exer08-exec-service-v1b.hpp
│       ├── exer08-exec-service-v2a.hpp
│       ├── exer08-exec-service-v2b.hpp
│       ├── exerex-countdown-timer.cpp
│       ├── mylib-blockingqueue.hpp
│       ├── mylib-execservice.hpp
│       ├── mylib-random.hpp
│       └── mylib-time.hpp
├── csharp/
│   ├── .gitignore
│   ├── IRunnable.cs
│   ├── Program.cs
│   ├── demo/
│   │   ├── demo00-intro.cs
│   │   ├── demo01a-hello.cs
│   │   ├── demo01b01-hello.cs
│   │   ├── demo01b02-hello.cs
│   │   ├── demo01ex-name.cs
│   │   ├── demo02a-join.cs
│   │   ├── demo02b-join.cs
│   │   ├── demo03a-pass-arg.cs
│   │   ├── demo03b-pass-arg.cs
│   │   ├── demo03c-pass-arg.cs
│   │   ├── demo03d-pass-arg.cs
│   │   ├── demo04-sleep.cs
│   │   ├── demo05-id.cs
│   │   ├── demo06a-list-threads.cs
│   │   ├── demo06b-list-threads.cs
│   │   ├── demo07-terminate.cs
│   │   ├── demo08a-return-value.cs
│   │   ├── demo08b-return-value.cs
│   │   ├── demo09-detach.cs
│   │   ├── demo10-yield.cs
│   │   ├── demo11a01-exec-service.cs
│   │   ├── demo11a02-exec-service.cs
│   │   ├── demo11a03-exec-service.cs
│   │   ├── demo11a04-exec-service.cs
│   │   ├── demo11a05-exec-service.cs
│   │   ├── demo11b01-exec-service-parallel.cs
│   │   ├── demo11b02-exec-service-parallel.cs
│   │   ├── demo11c-exec-service.cs
│   │   ├── demo12a-race-condition.cs
│   │   ├── demo12b01-data-race-single.cs
│   │   ├── demo12b02-data-race-multi.cs
│   │   ├── demo12c01-race-cond-data-race.cs
│   │   ├── demo12c02-race-cond-data-race.cs
│   │   ├── demo13a-mutex.cs
│   │   ├── demo13b-mutex-trylock.cs
│   │   ├── demo14-synchronized-block.cs
│   │   ├── demo15a-deadlock.cs
│   │   ├── demo15b-deadlock.cs
│   │   ├── demo16-monitor.cs
│   │   ├── demo17a-reentrant-lock.cs
│   │   ├── demo17b-reentrant-lock.cs
│   │   ├── demo18a01-barrier.cs
│   │   ├── demo18a03-barrier.cs
│   │   ├── demo18b01-latch.cs
│   │   ├── demo18b02-latch.cs
│   │   ├── demo19-read-write-lock.cs
│   │   ├── demo20a01-semaphore.cs
│   │   ├── demo20a02-semaphore.cs
│   │   ├── demo20a03-semaphore-deadlock.cs
│   │   ├── demo20b-semaphore.cs
│   │   ├── demo21a01-condition-variable.cs
│   │   ├── demo21a02-condition-variable.cs
│   │   ├── demo21a03-condition-variable.cs
│   │   ├── demo21b-condition-variable.cs
│   │   ├── demo22a-blocking-queue.cs
│   │   ├── demo22b-blocking-queue.cs
│   │   ├── demo23a01-thread-local.cs
│   │   ├── demo23a02-thread-local.cs
│   │   ├── demo23b-thread-local.cs
│   │   ├── demo24-volatile.cs
│   │   ├── demo25a-atomic.cs
│   │   └── demo25b-atomic.cs
│   ├── demoex/
│   │   ├── demoex-async-future-a01.cs
│   │   ├── demoex-async-future-a02.cs
│   │   ├── demoex-async-future-a03.cs
│   │   ├── demoex-async-future-a04.cs
│   │   ├── demoex-async-future-a05.cs
│   │   ├── demoex-async-future-b01.cs
│   │   ├── demoex-async-future-b02.cs
│   │   ├── demoex-async-future-b03.cs
│   │   ├── demoex-async-future-b04.cs
│   │   ├── demoex-async-future-c01.cs
│   │   └── demoex-async-future-c02.cs
│   ├── exercise/
│   │   ├── exer01a-max-div.cs
│   │   ├── exer01b-max-div.cs
│   │   ├── exer01c-max-div.cs
│   │   ├── exer02a01-producer-consumer.cs
│   │   ├── exer02a02-producer-consumer.cs
│   │   ├── exer02a03-producer-consumer.cs
│   │   ├── exer02a04-producer-consumer.cs
│   │   ├── exer02b01-producer-consumer.cs
│   │   ├── exer02b02-producer-consumer.cs
│   │   ├── exer02b03-producer-consumer.cs
│   │   ├── exer02b04-producer-consumer.cs
│   │   ├── exer02c-producer-consumer.cs
│   │   ├── exer03a-readers-writers.cs
│   │   ├── exer03b-readers-writers.cs
│   │   ├── exer04a-dining-philosophers.cs
│   │   ├── exer04b-dining-philosophers.cs
│   │   ├── exer05-util.cs
│   │   ├── exer05a-product-matrix-vector.cs
│   │   ├── exer05b-product-matrix-matrix.cs
│   │   ├── exer06a-blocking-queue.cs
│   │   ├── exer06b01-blocking-queue.cs
│   │   ├── exer06b02-blocking-queue.cs
│   │   ├── exer07a-data-server.cs
│   │   ├── exer07b-data-server.cs
│   │   ├── exer07c-data-server.cs
│   │   ├── exer07d-data-server.cs
│   │   ├── exer08-exec-service-main.cs
│   │   ├── exer08-exec-service-v0a.cs
│   │   ├── exer08-exec-service-v0b.cs
│   │   ├── exer08-exec-service-v1a.cs
│   │   ├── exer08-exec-service-v1b.cs
│   │   ├── exer08-exec-service-v2a.cs
│   │   └── exer08-exec-service-v2b.cs
│   ├── multithreading.csproj
│   └── multithreading.sln
├── java/
│   ├── .gitignore
│   ├── README.md
│   └── src/
│       ├── demo00_intro/
│       │   └── App.java
│       ├── demo01_hello/
│       │   ├── AppA01.java
│       │   ├── AppA02.java
│       │   ├── AppB01.java
│       │   ├── AppB02.java
│       │   ├── AppB03.java
│       │   ├── AppC01.java
│       │   ├── AppC02.java
│       │   └── AppExtra.java
│       ├── demo02_join/
│       │   ├── AppA.java
│       │   └── AppB.java
│       ├── demo03_pass_arg/
│       │   ├── AppA.java
│       │   ├── AppB.java
│       │   └── AppC.java
│       ├── demo04_sleep/
│       │   └── App.java
│       ├── demo05_id/
│       │   └── App.java
│       ├── demo06_list_threads/
│       │   ├── AppA.java
│       │   ├── AppB01.java
│       │   └── AppB02.java
│       ├── demo07_terminate/
│       │   ├── AppA.java
│       │   └── AppB.java
│       ├── demo08_return_value/
│       │   ├── AppA.java
│       │   ├── AppB.java
│       │   └── AppC.java
│       ├── demo09_detach/
│       │   └── App.java
│       ├── demo10_yield/
│       │   └── App.java
│       ├── demo11_exec_service/
│       │   ├── AppA.java
│       │   ├── AppB01.java
│       │   ├── AppB02.java
│       │   ├── AppC01.java
│       │   ├── AppC02.java
│       │   ├── AppC03.java
│       │   ├── AppC04.java
│       │   ├── AppC05.java
│       │   ├── AppC06.java
│       │   └── AppExtra.java
│       ├── demo12_race_condition/
│       │   ├── AppA.java
│       │   ├── AppB01.java
│       │   ├── AppB02.java
│       │   ├── AppC01.java
│       │   └── AppC02.java
│       ├── demo13_mutex/
│       │   ├── AppA.java
│       │   └── AppB.java
│       ├── demo14_synchronized_block/
│       │   ├── AppA.java
│       │   ├── AppB01.java
│       │   ├── AppB02.java
│       │   └── AppC.java
│       ├── demo15_deadlock/
│       │   ├── AppA.java
│       │   └── AppB.java
│       ├── demo16_monitor/
│       │   └── App.java
│       ├── demo17_reentrant_lock/
│       │   ├── AppA01.java
│       │   ├── AppA02.java
│       │   ├── AppB01.java
│       │   └── AppB02.java
│       ├── demo18_barrier_latch/
│       │   ├── AppA01.java
│       │   ├── AppA02.java
│       │   ├── AppA03.java
│       │   ├── AppB01.java
│       │   └── AppB02.java
│       ├── demo19_read_write_lock/
│       │   └── App.java
│       ├── demo20_semaphore/
│       │   ├── AppA01.java
│       │   ├── AppA02.java
│       │   ├── AppA03.java
│       │   └── AppB.java
│       ├── demo21_condition_variable/
│       │   ├── AppA01.java
│       │   ├── AppA02.java
│       │   ├── AppA03.java
│       │   └── AppB.java
│       ├── demo22_blocking_queue/
│       │   ├── AppA.java
│       │   ├── AppB.java
│       │   └── AppExtra.java
│       ├── demo23_thread_local/
│       │   ├── AppA01.java
│       │   ├── AppA02.java
│       │   └── AppB.java
│       ├── demo24_volatile/
│       │   └── App.java
│       ├── demo25_atomic/
│       │   ├── AppA.java
│       │   └── AppB.java
│       ├── demoex/
│       │   └── async/
│       │       ├── AppA.java
│       │       ├── AppB01.java
│       │       ├── AppB02.java
│       │       ├── AppB03.java
│       │       ├── AppB04.java
│       │       ├── AppC01.java
│       │       └── AppC02.java
│       ├── exer01_max_div/
│       │   ├── AppA.java
│       │   ├── AppB.java
│       │   └── AppC.java
│       ├── exer02_producer_consumer/
│       │   ├── AppA01.java
│       │   ├── AppA02.java
│       │   ├── AppA03.java
│       │   ├── AppA04.java
│       │   ├── AppB01.java
│       │   ├── AppB02.java
│       │   ├── AppB03.java
│       │   ├── AppB04.java
│       │   └── AppC.java
│       ├── exer03_readers_writers/
│       │   ├── AppA.java
│       │   └── AppB.java
│       ├── exer04_dining_philosophers/
│       │   ├── AppA.java
│       │   └── AppB.java
│       ├── exer05_product_matrix/
│       │   ├── AppA.java
│       │   ├── AppB.java
│       │   └── MyUtil.java
│       ├── exer06_blocking_queue/
│       │   ├── AppA.java
│       │   ├── AppB01.java
│       │   └── AppB02.java
│       ├── exer07_data_server/
│       │   ├── AppA.java
│       │   ├── AppB.java
│       │   ├── AppC.java
│       │   └── AppD.java
│       └── exer08_exec_service/
│           ├── App.java
│           ├── MyExecServiceV0A.java
│           ├── MyExecServiceV0B.java
│           ├── MyExecServiceV1A.java
│           ├── MyExecServiceV1B.java
│           ├── MyExecServiceV2A.java
│           └── MyExecServiceV2B.java
├── js-nodejs/
│   ├── .gitignore
│   ├── demo00.js
│   ├── demo01a-hello.js
│   ├── demo01b-hello-worker.js
│   ├── demo01b-hello.js
│   ├── demo02-join.js
│   ├── demo03a-pass-arg.js
│   ├── demo03b-pass-arg.js
│   ├── demo04-sleep.js
│   ├── demo05-id.js
│   ├── demo06a-list-threads.js
│   ├── demo06b-list-threads.js
│   ├── demo07-terminate.js
│   ├── demo08a-return-value.js
│   ├── demo08b-return-value.js
│   ├── demo11a-exec-service.js
│   ├── demo11b-exec-service.js
│   ├── demo12-race-condition.js
│   ├── demo12b01-data-race-single.js
│   ├── demo12b02-data-race-multi.js
│   ├── demo12c-race-cond-data-race.js
│   ├── demo13-mutex.js
│   ├── demo13ex-mutex-problem.js
│   ├── demo13ex-mutex-solve.js
│   ├── demo15a-deadlock.js
│   ├── demo15b-deadlock.js
│   ├── demo15ex-deadlock.js
│   ├── demo25-atomic.js
│   ├── exer01a-max-div.js
│   ├── exer01c-max-div.js
│   ├── exerex-userhash-problem.js
│   ├── exerex-userhash-solve01.js
│   ├── exerex-userhash-solve02-faster.js
│   ├── exerex-userhash-solve03-faster.js
│   ├── exerex-userhash-util.js
│   ├── mylib.js
│   ├── mylib_mutex.js
│   └── package.json
├── notes-articles.md
├── notes-demos-exercises.md
├── old/
│   ├── cpppthread-reentrant-lock-a.cpp
│   ├── cpppthread-reentrant-lock-b.cpp
│   ├── cppstd-data-race.cpp
│   ├── cppstd-reentrant-lock-a.cpp
│   └── cppstd-reentrant-lock-b.cpp
├── python/
│   ├── .gitignore
│   ├── demo00.py
│   ├── demo01_hello.py
│   ├── demo01ex_name.py
│   ├── demo02a_join.py
│   ├── demo02b_join.py
│   ├── demo03a_pass_arg.py
│   ├── demo03b_pass_arg.py
│   ├── demo04_sleep.py
│   ├── demo05_id.py
│   ├── demo06_list_threads.py
│   ├── demo07_terminate.py
│   ├── demo08a_return_value.py
│   ├── demo08b_return_value.py
│   ├── demo09_detach.py
│   ├── demo10_yield.py
│   ├── demo11a_exec_service.py
│   ├── demo11b_exec_service.py
│   ├── demo11c01_exec_service.py
│   ├── demo11c02_exec_service.py
│   ├── demo12a_race_condition.py
│   ├── demo12b01_data_race_single.py
│   ├── demo12b02_data_race_multi.py
│   ├── demo12c01_race_cond_data_race.py
│   ├── demo12c02_race_cond_data_race.py
│   ├── demo13a_mutex.py
│   ├── demo14_synchronized_block.py
│   ├── demo15a_deadlock.py
│   ├── demo15b_deadlock.py
│   ├── demo16_monitor.py
│   ├── demo17a_reentrant_lock.py
│   ├── demo17b_reentrant_lock.py
│   ├── demo17c_reentrant_lock.py
│   ├── demo18a01_barrier.py
│   ├── demo18a02_barrier.py
│   ├── demo18a03_barrier.py
│   ├── demo18b01_latch.py
│   ├── demo18b02_latch.py
│   ├── demo19_read_write_lock.py
│   ├── demo20a01_semaphore.py
│   ├── demo20a02_semaphore.py
│   ├── demo20a03_semaphore_deadlock.py
│   ├── demo20b_semaphore.py
│   ├── demo21a01_condition_variable.py
│   ├── demo21a02_condition_variable.py
│   ├── demo21a03_condition_variable.py
│   ├── demo21b_condition_variable.py
│   ├── demo22a_blocking_queue.py
│   ├── demo22b_blocking_queue.py
│   ├── demo23a_thread_local.py
│   ├── demo23b_thread_local.py
│   ├── demo24_volatile.py
│   ├── demo25_atomic.py
│   ├── demoex_event.py
│   ├── demoex_timer.py
│   ├── exer01a_max_div.py
│   ├── exer01b_max_div.py
│   ├── exer01c_max_div.py
│   ├── exer02a01_producer_consumer.py
│   ├── exer02a02_producer_consumer.py
│   ├── exer02a03_producer_consumer.py
│   ├── exer02a04_producer_consumer.py
│   ├── exer02b01_producer_consumer.py
│   ├── exer02b02_producer_consumer.py
│   ├── exer02b03_producer_consumer.py
│   ├── exer02b04_producer_consumer.py
│   ├── exer02c_producer_consumer.py
│   ├── exer03a_readers_writers.py
│   ├── exer03b_readers_writers.py
│   ├── exer04_dining_philosophers.py
│   ├── exer05a_product_matrix_vector.py
│   ├── exer05b_product_matrix_vector.py
│   ├── exer06a_blocking_queue.py
│   ├── exer06b01_blocking_queue.py
│   ├── exer06b02_blocking_queue.py
│   ├── exer07a_data_server.py
│   ├── exer07b_data_server.py
│   ├── exer07c_data_server.py
│   ├── exer07d_data_server.py
│   ├── exer08_exec_service_itask.py
│   ├── exer08_exec_service_main.py
│   ├── exer08_exec_service_v0a.py
│   ├── exer08_exec_service_v0b.py
│   ├── exer08_exec_service_v1a.py
│   ├── exer08_exec_service_v1b.py
│   ├── exer08_exec_service_v2a.py
│   ├── exer08_exec_service_v2b.py
│   ├── mylib_latch.py
│   ├── mylib_rwlock.py
│   └── mylib_rwlock2.py
└── references.md

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
.vscode/


================================================
FILE: LICENSE.txt
================================================
Copyright (c) 2021, Thanh Nguyen, thanh.it1995 (at) gmail.com
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

 - Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

 - Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

 - Neither the name of Thanh Nguyen nor the names of its contributors may
   be used to endorse or promote products derived from this software without
   specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


================================================
FILE: README.md
================================================
# MULTIPLE THREADING IN PRACTICE

## DESCRIPTION

This repo helps you to practise multithreading in a logical sequence, which is divided into several demonstrations.
Plus, you could apply your learning better by doing exercises.

The repo consists of two main sections:

- "demo" (demostrations).
- "exer" (exercises).

All the demos (and exers) are really simple, easy to understand, even for difficult terms.

If you find it helpful, please give my repo a star. Thank you.

 

## AUTHOR & LICENSE

Author: Thanh Nguyen

- Email: thanh.it1995@gmail.com
- Facebook: <https://www.facebook.com/thanh.it95>

This repo is licensed under the [3-Clause BSD License](LICENSE.txt).

&nbsp;

## LANGUAGES SUPPORTED

| Directory name | Description                  |
| -------------- | ---------------------------- |
| `cpp-std`      | C++20 std threading          |
| `cpp-pthread`  | C++11 POSIX threading        |
| `cpp-boost`    | C++98 Boost threading        |
| `csharp`       | C# 7.3 with Dot Net 6        |
| `java`         | Java JDK 17                  |
| `python`       | Python 3.10                  |
| `js-nodejs`    | Javascript ES2019/Nodejs 18  |

Special notes for C++ demos/exers: Please read the specified `readme.md` in corresponding directory.

&nbsp;

## THE NOTES AND ARTICLES

The notes and articles are the additional resources for the source code, which guides you for better research, step by step. You may consider it the comment/description at the beginning of the source code.

```text
  ORIGINAL SOURCE CODE FILE                  SOURCE CODE FILE              NOTES AND ARTICLES
------------------------------        ------------------------------     ----------------------
|                            |        |                            |     |                    |
| /* THE COMMENTS... */      |        |                            |     |    THE COMMENTS    |
|                            |        |                            |     |                    |
| #include <iostream>        |        | #include <iostream>        |     |                    |
| using namespace std;       |        | using namespace std;       |     |                    |
|                            |  ===>  |                            |  +  |                    |
| int main() {               |        | int main() {               |     |                    |
|   cout << "Hello thread";  |        |   cout << "Hello thread";  |     |                    |
|   return 0;                |        |   return 0;                |     |                    |
| }                          |        | }                          |     |                    |
|                            |        |                            |     |                    |
------------------------------        ------------------------------     ----------------------
```

There are 2 notes:

- [notes-demos-exercises.md](notes-demos-exercises.md): The notes that go along with original source code.
- [notes-articles.md](notes-articles.md): Extra helpful notes during my research.

&nbsp;

**For your best result, I strongly recommend that you read [notes-demos-exercises.md](notes-demos-exercises.md) while enjoying source code (demos and exercises).**

&nbsp;

## ROADMAP FOR THE LEARNERS

This is the roadmap for you, which is composed and researched carefully with all my heart. You should learn in the sequence listed below.

**If you just want to learn the basis to understand the taste of multithreading:**

- Demo: hello, join, pass arg, sleep, list-threads, race-condition, mutex, synchronized-block.
- Exer: max-div.

**If you are oriented to be a Software Developer:**

- Demo: hello, join, pass arg, sleep, list-threads, terminate, return-value, exec-service, race-condition, mutex, synchronized-block, deadlock, blocking-queue, atomic.
- Exer: max-div, producer-consumer, product-matrix, data-server.

**If you really want to do an in-depth research:** Learn all!!!

&nbsp;

---

## INTRODUCTION TO MULTITHREADING

### GETTING STARTED

Bob sends four messages to Alice: `I love`, `you`, `not`, `her`.

Surprisingly, Alice receives `I love`, `her`, `not`, `you` (That means "I love her not you"). So sad!

```text
TRADITIONAL (ONE THREAD)

    ===========================================> Time

                 Main thread
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>
      "I love"   "you"   "not"   "her"



MULTITHREADING (FOUR THREADS)

    ===========================================> Time

    ~~~~~~~~~~~~>
      "I love"

                      ~~~~~~~~~~~~>
                          "you"

              ~~~~~~~~~~~~>
                  "not"

        ~~~~~~~~~~~~>
            "her"
```

If you use multithreading or something similar, the context above is truly possible. The reason is that multithreading allows four messages to be sent in parallel, so message order is changed unpredictably when they come to Alice.

In a traditional simple app, there is only one thread (the "main thread"). If you apply multithreading then your app may have multiple threads (including the "main thread").

By learning multithreading:

- You get closer to the operating system.
- You can understand various terms: concurrency, parallel, asynchronous, synchronization.
- You have additional knowledge to learn asynchronous programming and parallel programming.

So, why multithreading?

### WHY MULTITHREADING

Multithreaded programs can improve performance compared to traditional simple programs (which use only a single thread).

Multithreading is used as an underlying technique in various fields:

- Web browsers (Chrome, Edge, Firefox...).
- Web servers.
- Graphic editors (Adobe Photoshop, Corel Draw...).
- Computer games.
- Database management systems.
- Networking programming.
- Video encoders.
- And more...

Benefits of multithreading:

- Improving application responsiveness.
  - Any program in which many activities are not dependent upon each other can be redesigned so that each activity is defined as a thread. For example, the user of a multithreaded GUI does not have to wait for one activity to complete before starting another.

- Using multiprocessors efficiently.
  - Typically, applications that express concurrency requirements with threads need not take into account the number of available processors. The performance of the application improves transparently with additional processors.
  - Numerical algorithms and applications with a high degree of parallelism, such as matrix multiplications, can run much faster when implemented with threads on a multiprocessor.

- Improving throughput.
  - Many concurrent compute operations and I/O requests within a single process.

- Program structure simplification.
  - Threads can be used to simplify the structure of complex applications, such as server-class and multimedia applications. Simple routines can be written for each activity, making complex programs easier to design and code, and more adaptive to a wide variation in user demands.

- Using fewer system resources.
  - Threads impose minimal impact on system resources. Threads require less overhead to create, maintain, and manage than a traditional process.

- Better communication.
  - Thread synchronization functions can be used to provide enhanced process-to-process communication.
  - In addition, sharing large amounts of data through separate threads of execution within the same address space provides extremely high-bandwidth, low-latency communication between separate tasks within an application.

&nbsp;

If you want to explore more articles, read here: [notes-articles.md](notes-articles.md).

&nbsp;

Article references:

- [Oracle Documentation Home, Multithreaded Programming Guide, Chapter 1 Covering Multithreading Basics, Benefiting From Multithreading](https://docs.oracle.com/cd/E19455-01/806-5257/6je9h032d/index.html)
- [Oracle Documentation Home, JDK 1.1 for Solaris Developer's Guide, Chapter 2 Multithreading, Benefits of Multithreading](https://docs.oracle.com/cd/E19455-01/806-3461/6jck06gqj/index.html)

&nbsp;

---

## REFERENCES

All general references in my repo.

Read here: [references.md](references.md).


================================================
FILE: cpp/.gitignore
================================================
a
a.out
tmp*


================================================
FILE: cpp/README.md
================================================
# C++ MULTITHREADING

## DESCRIPTION

Multithreading in C++.

&nbsp;

## PROJECT STRUCTURE

| Directory name | Description           | Notes |
| -------------- | --------------------- | ----- |
| `cpp-std`      | C++20 std threading   | Most source code files are in C++11. Some features require newer standard. |
| `cpp-pthread`  | C++11 POSIX threading |       |
| `cpp-boost`    | C++98 Boost threading |       |

&nbsp;

## COMPILATION

Ensure that your compiler meets the C++ standard as mentioned above.

### gcc compiler

To compile with specified C++ standard, use option `-std`:

- C++98: `g++ -o exec_filename filename.cpp -std=c++98`
- C++11: `g++ -o exec_filename filename.cpp -std=c++11`
- C++20: `g++ -o exec_filename filename.cpp -std=c++20`

Usually in Linux/Unix environments, we shall use POSIX threading. This leads to linking objects with pthread by option `-lpthread`.

Additionally, if you use Boost:

- `-lboost_thread` for all code.
- `-lboost_chrono` for the code using boost::chrono.
- `-lboost_random` for the code using boost::random.

&nbsp;

Example 1:

```shell
# Compile
g++ -o output_exe demo00.cpp -lpthread -std=c++20

# Run
./output_exe
```

Example 2 for lib Boost:

```shell
# Compile
g++ -o output_exe demo04a-sleep.cpp -lpthread -lboost_thread -lboost_chrono

# Run
./output_exe
```

&nbsp;

### Other compilers and/or environments

You may consider a suitable IDE/compiler (e.g. Microsoft Visual Studio, mingw...).


================================================
FILE: cpp/cpp-boost/demo00.cpp
================================================
/*
INTRODUCTION TO MULTITHREADING
You should try running this app several times and see results.
*/


#include <iostream>
#include <boost/thread.hpp>
using namespace std;



void doTask() {
    for (int i = 0; i < 300; ++i)
        cout << "B";
}



int main() {
    boost::thread th(&doTask);

    for (int i = 0; i < 300; ++i)
        cout << "A";

    th.join();

    cout << endl;
    return 0;
}


================================================
FILE: cpp/cpp-boost/demo01a01-hello.cpp
================================================
/*
HELLO WORLD VERSION MULTITHREADING
Version A01: Using functions
*/


#include <iostream>
#include <boost/thread.hpp>
using namespace std;



void doTask() {
    cout << "Hello from example thread" << endl;
}



int main() {
    boost::thread th(&doTask);

    cout << "Hello from main thread" << endl;

    th.join();
    return 0;
}


================================================
FILE: cpp/cpp-boost/demo01a02-hello.cpp
================================================
/*
HELLO WORLD VERSION MULTITHREADING
Version A02: Using functions allowing passing 2 arguments
*/


#include <iostream>
#include <boost/thread.hpp>
using namespace std;



void doTask(char const* message, int number) {
    cout << message << " " << number << endl;
}



int main() {
    boost::thread th(&doTask, "Good day", 19);
    th.join();
    return 0;
}


================================================
FILE: cpp/cpp-boost/demo01b-hello-class01.cpp
================================================
/*
HELLO WORLD VERSION MULTITHREADING
Version B: Using class methods
*/


#include <iostream>
#include <string>
#include <boost/thread.hpp>
using namespace std;



class Example {
public:
    void doTask(string message) {
        cout << message << endl;
    }
};



int main() {
    Example example;

    boost::thread th(&Example::doTask, &example, "Good day");
    // boost::thread th(boost::bind(&Example::doTask, &example, "Good day"));

    th.join();
    return 0;
}


================================================
FILE: cpp/cpp-boost/demo01b-hello-class02.cpp
================================================
/*
HELLO WORLD VERSION MULTITHREADING
Version B: Using class methods
*/


#include <iostream>
#include <string>
#include <boost/bind/bind.hpp>
#include <boost/thread.hpp>
using namespace std;



class Example {
public:
    void run() {
        boost::thread th(&Example::doTask, this, "Good day");
        // boost::thread th(boost::bind(&Example::doTask, this, "Good day"));
        th.join();
    }

private:
    void doTask(string message) {
        cout << message << endl;
    }
};



int main() {
    Example example;
    example.run();
    return 0;
}


================================================
FILE: cpp/cpp-boost/demo01b-hello-class03.cpp
================================================
/*
HELLO WORLD VERSION MULTITHREADING
Version B: Using class methods
*/


#include <iostream>
#include <string>
#include <boost/thread.hpp>
using namespace std;



class Example {
public:
    void run() {
        boost::thread th(&Example::doTask, "Good day");
        th.join();
    }

private:
    static void doTask(string message) {
        cout << message << endl;
    }
};



int main() {
    Example example;
    example.run();
    return 0;
}


================================================
FILE: cpp/cpp-boost/demo01b-hello-functor.cpp
================================================
/*
HELLO WORLD VERSION MULTITHREADING
Version B: Using functors
*/


#include <iostream>
#include <string>
#include <boost/thread.hpp>
using namespace std;



class Example {
public:
    void operator()(string message) {
        cout << message << endl;
    }
};



int main() {
    Example example;

    boost::thread th(example, "Good day");

    th.join();
    return 0;
}


================================================
FILE: cpp/cpp-boost/demo02-join.cpp
================================================
/*
THREAD JOINS
*/


#include <iostream>
#include <boost/thread.hpp>
using namespace std;



void doHeavyTask() {
    // Do a heavy task, which takes a little time
    for (int i = 0; i < 2000000000; ++i);

    cout << "Done!" << endl;
}



int main() {
    boost::thread th(&doHeavyTask);

    th.join();

    cout << "Good bye!" << endl;

    return 0;
}


================================================
FILE: cpp/cpp-boost/demo03a-pass-arg.cpp
================================================
/*
PASSING ARGUMENTS
Version A: Passing multiple arguments with various data types
*/


#include <iostream>
#include <cstdio>
#include <string>
#include <boost/thread.hpp>
using namespace std;



struct Point {
    int x;
    int y;

    Point(int x, int y): x(x), y(y) { }
};



void doTask(int a, double b, string c, char const* d, Point e) {
    char buffer[50] = { 0 };
    std::sprintf(buffer, "%d  %.1f  %s  %s  (%d %d)", a, b, c.data(), d, e.x, e.y);
    cout << buffer << endl;
}



int main() {
    boost::thread thFoo(&doTask, 1, 2, "red", "red", Point(0, 0));
    boost::thread thBar(&doTask, 3, 4, "blue", "blue", Point(9, 9));

    thFoo.join();
    thBar.join();

    return 0;
}


================================================
FILE: cpp/cpp-boost/demo03b-pass-arg.cpp
================================================
/*
PASSING ARGUMENTS
Version B: Passing constant references
*/


#include <iostream>
#include <string>
#include <boost/thread.hpp>
using namespace std;



void doTask(const string& msg) {
    cout << msg << endl;
}

void doTask(const string& msg) {
    cout << msg << endl;
}



int main() {
    boost::thread thFoo(&doTask, "foo");
    boost::thread thBar(&doTask, "bar");

    thFoo.join();
    thBar.join();

    return 0;
}


================================================
FILE: cpp/cpp-boost/demo03c-pass-arg.cpp
================================================
/*
PASSING ARGUMENTS
Version C: Passing normal references
*/


#include <iostream>
#include <string>
#include <boost/ref.hpp>
#include <boost/thread.hpp>
using namespace std;



void doTask(string& msg) {
    cout << msg << endl;
}



int main() {
    string a = "lorem ipsum";
    string b = "dolor amet";

    // We should use boost:ref to pass references
    boost::thread thFoo(&doTask, boost::ref(a));
    boost::thread thBar(&doTask, boost::ref(b));

    // boost::thread thFoo(&doTask, a);
    // boost::thread thBar(&doTask, b);

    thFoo.join();
    thBar.join();

    return 0;
}


================================================
FILE: cpp/cpp-boost/demo04a-sleep.cpp
================================================
/*
SLEEP
Version A: Sleep for a specific duration
*/


#include <iostream>
#include <string>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
using namespace std;



void doTask(string name) {
    cout << name << " is sleeping" << endl;
    boost::this_thread::sleep_for(boost::chrono::seconds(3));
    cout << name << " wakes up" << endl;
}



int main() {
    boost::thread thFoo(&doTask, "foo");

    thFoo.join();

    cout << "Good bye" << endl;
    return 0;
}


================================================
FILE: cpp/cpp-boost/demo04b-sleep.cpp
================================================
/*
SLEEP
Version B: Sleep until a specific time point
*/


#include <iostream>
#include <string>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include "mylib-time.hpp"
using namespace std;



typedef boost::chrono::system_clock sysclock;



void doTask(string name, sysclock::time_point tpWakeUp) {
    boost::this_thread::sleep_until(tpWakeUp);
    cout << name << " wakes up" << endl;
}



int main() {
    sysclock::time_point tpNow = sysclock::now();
    sysclock::time_point tpWakeUpFoo = tpNow + boost::chrono::seconds(7);
    sysclock::time_point tpWakeUpBar = tpNow + boost::chrono::seconds(3);

    cout << "foo will sleep until " << mylib::getTimePointStr(tpWakeUpFoo) << endl;
    cout << "bar will sleep until " << mylib::getTimePointStr(tpWakeUpBar) << endl;

    boost::thread thFoo(&doTask, "foo", tpWakeUpFoo);
    boost::thread thBar(&doTask, "bar", tpWakeUpBar);

    thFoo.join();
    thBar.join();

    return 0;
}


================================================
FILE: cpp/cpp-boost/demo05-id.cpp
================================================
/*
GETTING THREAD'S ID
*/


#include <iostream>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
using namespace std;



void doTask() {
    boost::this_thread::sleep_for(boost::chrono::seconds(2));
    cout << boost::this_thread::get_id() << endl;
}



int main() {
    boost::thread thFoo(&doTask);
    boost::thread thBar(&doTask);

    cout << "foo's id: " << thFoo.get_id() << endl;
    cout << "bar's id: " << thBar.get_id() << endl;

    thFoo.join();
    thBar.join();

    return 0;
}


================================================
FILE: cpp/cpp-boost/demo06a-list-threads.cpp
================================================
/*
LIST OF MULTIPLE THREADS
Version A: Using standard arrays
*/


#include <iostream>
#include <boost/thread.hpp>
using namespace std;



void doTask(int index) {
    cout << index;
}



int main() {
    const int NUM_THREADS = 5;

    boost::thread lstTh[NUM_THREADS];

    for (int i = 0; i < NUM_THREADS; ++i) {
        lstTh[i] = boost::thread(&doTask, i);
    }

    for (int i = 0; i < NUM_THREADS; ++i) {
        lstTh[i].join();
    }

    cout << endl;
    return 0;
}


================================================
FILE: cpp/cpp-boost/demo06b-list-threads.cpp
================================================
/*
LIST OF MULTIPLE THREADS
Version B: Using the std::vector
*/


#include <iostream>
#include <vector>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
using namespace std;



typedef boost::shared_ptr<boost::thread> threadptr;



void doTask(int index) {
    cout << index;
}



int main() {
    const int NUM_THREADS = 5;

    vector<threadptr> lstTh;

    for (int i = 0; i < NUM_THREADS; ++i) {
        threadptr ptr = boost::make_shared<boost::thread>(&doTask, i);
        lstTh.push_back(ptr);
    }

    for (int i = 0; i < lstTh.size(); ++i) {
        lstTh[i]->join();
    }

    cout << endl;
    return 0;
}


================================================
FILE: cpp/cpp-boost/demo06c-list-threads.cpp
================================================
/*
LIST OF MULTIPLE THREADS
Version C: Using the boost::thread_group
*/


#include <iostream>
#include <boost/bind/bind.hpp>
#include <boost/thread.hpp>
using namespace std;



void doTask(int index) {
    cout << index;
}



int main() {
    const int NUM_THREADS = 5;

    boost::thread_group lstTh;

    for (int i = 0; i < NUM_THREADS; ++i) {
        lstTh.add_thread(new boost::thread(&doTask, i));
        // lstTh.create_thread(boost::bind(&doTask, i));
    }

    lstTh.join_all();

    cout << endl;
    return 0;
}


================================================
FILE: cpp/cpp-boost/demo07-terminate.cpp
================================================
/*
FORCING A THREAD TO TERMINATE (i.e. killing the thread)
*/


#include <iostream>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
using namespace std;



volatile bool isRunning;



void doTask() {
    while (isRunning) {
        cout << "Running..." << endl;
        boost::this_thread::sleep_for(boost::chrono::seconds(2));
    }
}



int main() {
    isRunning = true;
    boost::thread th(&doTask);

    boost::this_thread::sleep_for(boost::chrono::seconds(6));
    isRunning = false;

    th.join();
    return 0;
}


================================================
FILE: cpp/cpp-boost/demo08-return-value.cpp
================================================
/*
GETTING RETURNED VALUES FROM THREADS
Using pointers or references (traditional way)
*/


#include <iostream>
#include <boost/ref.hpp>
#include <boost/thread.hpp>
using namespace std;



void doubleValue(int arg, int* res) {
    (*res) = arg * 2;
}



void squareValue(int arg, int& res) {
    res = arg * arg;
}



int main() {
    int result[3];

    boost::thread thFoo(&doubleValue, 5, &result[0]);
    boost::thread thBar(&doubleValue, 80, &result[1]);
    boost::thread thEgg(&squareValue, 7, boost::ref(result[2]));

    thFoo.join();
    thBar.join();
    thEgg.join();

    cout << result[0] << endl;
    cout << result[1] << endl;
    cout << result[2] << endl;

    return 0;
}


================================================
FILE: cpp/cpp-boost/demo09-detach.cpp
================================================
/*
THREAD DETACHING
*/


#include <iostream>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
using namespace std;



void foo() {
    cout << "foo is starting..." << endl;

    boost::this_thread::sleep_for(boost::chrono::seconds(2));

    cout << "foo is exiting..." << endl;
}



int main() {
    boost::thread thFoo(&foo);
    thFoo.detach();


    // If I comment this statement,
    // thFoo will be forced into terminating with main thread
    boost::this_thread::sleep_for(boost::chrono::seconds(3));


    cout << "Main thread is exiting" << endl;
    return 0;
}


================================================
FILE: cpp/cpp-boost/demo10-yield.cpp
================================================
/*
THREAD YIELDING
*/


#include <iostream>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include "mylib-time.hpp"
using namespace std;



typedef boost::chrono::microseconds chrmicro;
typedef boost::chrono::steady_clock::time_point time_point;
typedef mylib::HiResClock hrclock;



void littleSleep(int us) {
    time_point tpStart = hrclock::now();
    time_point tpEnd = tpStart + chrmicro(us);

    do {
        boost::this_thread::yield();
    }
    while (hrclock::now() < tpEnd);
}



int main() {
    time_point tpStartMeasure = hrclock::now();

    littleSleep(130);

    chrmicro timeElapsed = hrclock::getTimeSpan<chrmicro>(tpStartMeasure);

    cout << "Elapsed time: " << timeElapsed.count() << " microseonds" << endl;
    return 0;
}


================================================
FILE: cpp/cpp-boost/demo11a-exec-service.cpp
================================================
/*
EXECUTOR SERVICES AND THREAD POOLS
*/


#include <iostream>
#include <boost/bind/bind.hpp>
#include <boost/thread.hpp>
#include <boost/asio.hpp>
using namespace std;



void doTask() {
    cout << "Hello the Executor Service" << endl;
}



class MyFunctor {
public:
    void operator()() {
        cout << "Hello Multithreading" << endl;
    }
};



int main() {
    // INIT THE EXECUTOR SERVICE WITH 2 THREADS
    boost::asio::thread_pool pool(2);


    // SUBMIT
    boost::asio::post(pool, boost::bind(&doTask /* , argument1, argument2,... */));
    boost::asio::post(pool, MyFunctor());


    // WAIT FOR THE COMPLETION OF ALL TASKS AND SHUTDOWN EXECUTOR SERVICE
    pool.join();
    pool.stop();

    return 0;
}


================================================
FILE: cpp/cpp-boost/demo11b-exec-service.cpp
================================================
/*
EXECUTOR SERVICES AND THREAD POOLS
*/


#include <iostream>
#include <boost/bind/bind.hpp>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include <boost/asio.hpp>
using namespace std;



void doTask(char id) {
    cout << "Task " << id << " is starting" << endl;
    boost::this_thread::sleep_for(boost::chrono::seconds(3));
    cout << "Task " << id << " is completed" << endl;
}



int main() {
    const int NUM_THREADS = 2;
    const int NUM_TASKS = 5;

    boost::asio::thread_pool pool(NUM_THREADS);

    for (int i = 0; i < NUM_TASKS; ++i) {
        boost::asio::post(pool, boost::bind(&doTask, 'A' + i));
    }

    cout << "All tasks are submitted" << endl;

    pool.join();
    cout << "All tasks are completed" << endl;

    pool.stop();

    return 0;
}


================================================
FILE: cpp/cpp-boost/demo12a-race-condition.cpp
================================================
/*
RACE CONDITIONS
*/


#include <iostream>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
using namespace std;



void doTask(int index) {
    boost::this_thread::sleep_for(boost::chrono::seconds(1));
    cout << index;
}



int main() {
    const int NUM_THREADS = 4;
    boost::thread_group lstTh;

    for (int i = 0; i < NUM_THREADS; ++i) {
        lstTh.add_thread(new boost::thread(&doTask, i));
    }

    lstTh.join_all();

    cout << endl;
    return 0;
}


================================================
FILE: cpp/cpp-boost/demo12b01-data-race-single.cpp
================================================
/*
DATA RACES
Version 01: Without multithreading
*/


#include <iostream>
#include <vector>
#include <numeric>
using namespace std;



int getResult(int N) {
    vector<bool> a;
    a.resize(N + 1, false);

    for (int i = 1; i <= N; ++i)
        if (0 == i % 2 || 0 == i % 3)
            a[i] = true;

    // result = sum of a (i.e. counting number of true values in a)
    int result = std::accumulate(a.begin(), a.end(), 0);
    return result;
}



int main() {
    const int N = 8;

    int result = getResult(N);

    cout << "Number of integers that are divisible by 2 or 3 is: " << result << endl;
    return 0;
}


================================================
FILE: cpp/cpp-boost/demo12b02-data-race-multi.cpp
================================================
/*
DATA RACES
Version 02: Multithreading
*/


#include <iostream>
#include <vector>
#include <numeric>
#include <boost/ref.hpp>
#include <boost/thread.hpp>
using namespace std;



void markDiv2(vector<bool> & a, int N) {
    for (int i = 2; i <= N; i += 2)
        a[i] = true;
}



void markDiv3(vector<bool> & a, int N) {
    for (int i = 3; i <= N; i += 3)
        a[i] = true;
}



int main() {
    const int N = 8;

    vector<bool> a;
    a.resize(N + 1, false);

    boost::thread thDiv2(&markDiv2, boost::ref(a), N);
    boost::thread thDiv3(&markDiv3, boost::ref(a), N);
    thDiv2.join();
    thDiv3.join();

    // result = sum of a (i.e. counting numbers of true values in a)
    int result = std::accumulate(a.begin(), a.end(), 0);

    cout << "Number of integers that are divisible by 2 or 3 is: " << result << endl;
    return 0;
}


================================================
FILE: cpp/cpp-boost/demo12c01-race-cond-data-race.cpp
================================================
/*
RACE CONDITIONS AND DATA RACES
*/


#include <iostream>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
using namespace std;



int counter = 0;



void increaseCounter() {
    boost::this_thread::sleep_for(boost::chrono::seconds(1));

    for (int i = 0; i < 1000; ++i) {
        counter += 1;
    }
}



int main() {
    const int NUM_THREADS = 16;
    boost::thread_group lstTh;

    for (int i = 0; i < NUM_THREADS; ++i) {
        lstTh.add_thread(new boost::thread(&increaseCounter));
    }

    lstTh.join_all();

    cout << "counter = " << counter << endl;
    // We are NOT sure that counter = 16000

    return 0;
}


================================================
FILE: cpp/cpp-boost/demo12c02-race-cond-data-race.cpp
================================================
/*
RACE CONDITIONS AND DATA RACES
*/


#include <iostream>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
using namespace std;



typedef boost::chrono::system_clock sysclock;



int counter = 0;



void doTaskA(sysclock::time_point timePointWakeUp) {
    boost::this_thread::sleep_until(timePointWakeUp);

    while (counter < 10)
        ++counter;

    cout << "A won !!!" << endl;
}



void doTaskB(sysclock::time_point timePointWakeUp) {
    boost::this_thread::sleep_until(timePointWakeUp);

    while (counter > -10)
        --counter;

    cout << "B won !!!" << endl;
}



int main() {
    sysclock::time_point tpNow = sysclock::now();
    sysclock::time_point tpWakeUp = tpNow + boost::chrono::seconds(1);

    boost::thread thA(&doTaskA, tpWakeUp);
    boost::thread thB(&doTaskB, tpWakeUp);

    thA.join();
    thB.join();

    return 0;
}


================================================
FILE: cpp/cpp-boost/demo13a-mutex.cpp
================================================
/*
MUTEXES
*/


#include <iostream>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
using namespace std;



boost::mutex mut;
int counter = 0;



void doTask() {
    boost::this_thread::sleep_for(boost::chrono::seconds(1));

    mut.lock();

    for (int i = 0; i < 1000; ++i)
        ++counter;

    mut.unlock();
}



int main() {
    const int NUM_THREADS = 16;
    boost::thread_group lstTh;

    for (int i = 0; i < NUM_THREADS; ++i) {
        lstTh.add_thread(new boost::thread(&doTask));
    }

    lstTh.join_all();

    cout << "counter = " << counter << endl;
    // We are sure that counter = 16000

    return 0;
}


================================================
FILE: cpp/cpp-boost/demo13b01-mutex.cpp
================================================
/*
MUTEXES
*/


#include <iostream>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
using namespace std;



boost::mutex mut;
int counter = 0;



void doTask() {
    boost::this_thread::sleep_for(boost::chrono::seconds(1));

    boost::lock_guard<boost::mutex> lk(mut);

    for (int i = 0; i < 1000; ++i)
        ++counter;

    // Once function exits, then destructor of lk object will be called.
    // In destructor it unlocks the mutex.
}



int main() {
    const int NUM_THREADS = 16;
    boost::thread_group lstTh;

    for (int i = 0; i < NUM_THREADS; ++i) {
        lstTh.add_thread(new boost::thread(&doTask));
    }

    lstTh.join_all();

    cout << "counter = " << counter << endl;
    // We are sure that counter = 16000

    return 0;
}


================================================
FILE: cpp/cpp-boost/demo13b02-mutex.cpp
================================================
/*
MUTEXES

boost::unique_lock is more complex than boost::lock_guard:
Not only does it provide for RAII-style locking, it also allows for
deferring acquiring the lock until the lock() member function is called explicitly,
or trying to acquire the lock in a non-blocking fashion, or with a timeout.

Consequently, unlock() is only called in the destructor if the lock object
has locked the Lockable object, or otherwise adopted a lock on the Lockable object.

(From Boost's docs website)
*/


#include <iostream>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
using namespace std;



boost::mutex mut;
int counter = 0;



void doTask() {
    boost::this_thread::sleep_for(boost::chrono::seconds(1));

    boost::unique_lock<boost::mutex> lk(mut);

    for (int i = 0; i < 1000; ++i)
        ++counter;
}



int main() {
    const int NUM_THREADS = 16;
    boost::thread_group lstTh;

    for (int i = 0; i < NUM_THREADS; ++i) {
        lstTh.add_thread(new boost::thread(&doTask));
    }

    lstTh.join_all();

    cout << "counter = " << counter << endl;
    // We are sure that counter = 16000

    return 0;
}


================================================
FILE: cpp/cpp-boost/demo13c-mutex-trylock.cpp
================================================
/*
MUTEXES
Locking with a nonblocking mutex
*/


#include <iostream>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
using namespace std;



boost::mutex mut;
int counter = 0;



void doTask() {
    boost::this_thread::sleep_for(boost::chrono::seconds(1));

    if (false == mut.try_lock()) {
        return;
    }

    for (int i = 0; i < 10000; ++i)
        ++counter;

    mut.unlock();
}



int main() {
    const int NUM_THREADS = 3;
    boost::thread_group lstTh;

    for (int i = 0; i < NUM_THREADS; ++i) {
        lstTh.add_thread(new boost::thread(&doTask));
    }

    lstTh.join_all();

    cout << "counter = " << counter << endl;
    // counter can be 10000, 20000 or 30000

    return 0;
}


================================================
FILE: cpp/cpp-boost/demo14-synchronized-block.cpp
================================================
/*
SYNCHRONIZED BLOCKS

Synchronized blocks in C++ Boost threading are not supported by default.
To demonstate synchronized blocks, I use boost::unique_lock (or boost::lock_guard).

Now, let's see the code:
    {
        boost::unique_lock lk(mut);
        // Do something in the critical section
    }

The code block above is protected by a lock/mutex. That means it is synchronized on thread execution.
This code block is called "the synchronized block".
*/


#include <iostream>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
using namespace std;



boost::mutex mut;
int counter = 0;



void doTask() {
    boost::this_thread::sleep_for(boost::chrono::seconds(1));

    // This is the "synchronized block"
    {
        boost::unique_lock<boost::mutex> lk(mut);

        for (int i = 0; i < 1000; ++i)
            ++counter;
    }
}



int main() {
    const int NUM_THREADS = 16;
    boost::thread_group lstTh;

    for (int i = 0; i < NUM_THREADS; ++i) {
        lstTh.add_thread(new boost::thread(&doTask));
    }

    lstTh.join_all();

    cout << "counter = " << counter << endl;
    // We are sure that counter = 16000

    return 0;
}


================================================
FILE: cpp/cpp-boost/demo15a-deadlock.cpp
================================================
/*
DEADLOCK
Version A
*/


#include <iostream>
#include <string>
#include <boost/thread.hpp>
using namespace std;



boost::mutex mut;



void doTask(std::string name) {
    mut.lock();

    cout << name << " acquired resource" << endl;

    // mut.unlock(); // Forget this statement ==> deadlock
}



int main() {
    boost::thread thFoo(&doTask, "foo");
    boost::thread thBar(&doTask, "bar");

    thFoo.join();
    thBar.join();

    cout << "You will never see this statement due to deadlock!" << endl;
    return 0;
}


================================================
FILE: cpp/cpp-boost/demo15b-deadlock.cpp
================================================
/*
DEADLOCK
Version B
*/


#include <iostream>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
using namespace std;



boost::mutex mutResourceA;
boost::mutex mutResourceB;



void foo() {
    mutResourceA.lock();
    cout << "foo acquired resource A" << endl;

    boost::this_thread::sleep_for(boost::chrono::seconds(1));

    mutResourceB.lock();
    cout << "foo acquired resource B" << endl;
    mutResourceB.unlock();

    mutResourceA.unlock();
}



void bar() {
    mutResourceB.lock();
    cout << "bar acquired resource B" << endl;

    boost::this_thread::sleep_for(boost::chrono::seconds(1));

    mutResourceA.lock();
    cout << "bar acquired resource A" << endl;
    mutResourceA.unlock();

    mutResourceB.unlock();
}



int main() {
    boost::thread thFoo(&foo);
    boost::thread thBar(&bar);

    thFoo.join();
    thBar.join();

    cout << "You will never see this statement due to deadlock!" << endl;
    return 0;
}


================================================
FILE: cpp/cpp-boost/demo16-monitor.cpp
================================================
/*
MONITORS
Implementation of a monitor for managing a counter
*/


#include <iostream>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
using namespace std;



class Monitor {
private:
    boost::mutex mut;
    int* pCounter;


public:
    // Should disable copy/move constructors, copy/move assignment operators


    void init(int* pCounter) {
        this->pCounter = pCounter;
    }


    void increaseCounter() {
        mut.lock();
        (*pCounter) += 1;
        mut.unlock();
    }
};



void doTask(Monitor* monitor) {
    boost::this_thread::sleep_for(boost::chrono::seconds(1));

    for (int i = 0; i < 1000; ++i)
        monitor->increaseCounter();
}



int main() {
    int counter = 0;
    Monitor monitor;

    const int NUM_THREADS = 16;
    boost::thread_group lstTh;

    monitor.init(&counter);

    for (int i = 0; i < NUM_THREADS; ++i) {
        lstTh.add_thread(new boost::thread(&doTask, &monitor));
    }

    lstTh.join_all();

    cout << "counter = " << counter << endl;
    return 0;
}


================================================
FILE: cpp/cpp-boost/demo17a-reentrant-lock.cpp
================================================
/*
REENTRANT LOCKS (RECURSIVE MUTEXES)
Version A: Introduction to reentrant locks
*/


#include <iostream>
#include <boost/thread.hpp>
using namespace std;



boost::mutex mut;



void doTask() {
    mut.lock();
    cout << "First time acquiring the resource" << endl;

    mut.lock();
    cout << "Second time acquiring the resource" << endl;

    mut.unlock();
    mut.unlock();
}



int main() {
    boost::thread th(&doTask);
    /*
    The thread th shall meet deadlock.
    So, you will never get output "Second time the acquiring resource".
    */
    th.join();
    return 0;
}


================================================
FILE: cpp/cpp-boost/demo17b-reentrant-lock.cpp
================================================
/*
REENTRANT LOCKS (RECURSIVE MUTEXES)
Version B: Solving the problem from version A
*/


#include <iostream>
#include <boost/thread.hpp>
using namespace std;



boost::recursive_mutex mut;



void doTask() {
    mut.lock();
    cout << "First time acquiring the resource" << endl;

    mut.lock();
    cout << "Second time acquiring the resource" << endl;

    mut.unlock();
    mut.unlock();
}



void doTaskUsingSyncBlock() {
    typedef boost::unique_lock<boost::recursive_mutex> uniquelk;

    uniquelk(mut);
    cout << "First time acquiring the resource" << endl;

    {
        uniquelk(mut);
        cout << "Second time acquiring the resource" << endl;
    }
}



int main() {
    boost::thread th(&doTask);
    th.join();
    return 0;
}


================================================
FILE: cpp/cpp-boost/demo17c-reentrant-lock.cpp
================================================
/*
REENTRANT LOCKS (RECURSIVE MUTEXES)
Version C: A multithreaded app example
*/


#include <iostream>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
using namespace std;



boost::recursive_mutex mut;



void doTask(char name) {
    boost::this_thread::sleep_for(boost::chrono::seconds(1));

    mut.lock();
    cout << "First time " << name << " acquiring the resource" << endl;

    mut.lock();
    cout << "Second time " << name << " acquiring the resource" << endl;

    mut.unlock();
    mut.unlock();
}



void doTaskUsingSyncBlock(char name) {
    typedef boost::unique_lock<boost::recursive_mutex> uniquelk;

    boost::this_thread::sleep_for(boost::chrono::seconds(1));

    {
        uniquelk(mut);
        cout << "First time " << name << " acquiring the resource" << endl;

        {
            uniquelk(mut);
            cout << "Second time " << name << " acquiring the resource" << endl;
        }
    }
}



int main() {
    const int NUM_THREADS = 3;
    boost::thread_group lstTh;

    for (int i = 0; i < NUM_THREADS; ++i) {
        lstTh.add_thread(new boost::thread(&doTask, char(i + 'A')));
    }

    lstTh.join_all();

    return 0;
}


================================================
FILE: cpp/cpp-boost/demo18a01-barrier.cpp
================================================
/*
BARRIERS AND LATCHES
Version A: Cyclic barriers
*/


#include <iostream>
#include <string>
#include <boost/tuple/tuple.hpp>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
using namespace std;



typedef boost::tuple<string,int> tuplestrint;

boost::barrier syncPoint(3); // participant count = 3



void processRequest(string userName, int waitTime) {
    boost::this_thread::sleep_for(boost::chrono::seconds(waitTime));

    cout << "Get request from " << userName << endl;
    syncPoint.count_down_and_wait();

    cout << "Process request for " << userName << endl;
    syncPoint.count_down_and_wait();

    cout << "Done " << userName << endl;
}



int main() {
    const int NUM_THREADS = 3;
    boost::thread_group lstTh;

    // tuple<userName, waitTime>
    tuplestrint lstArg[NUM_THREADS] = {
        tuplestrint("lorem", 1),
        tuplestrint("ipsum", 2),
        tuplestrint("dolor", 3)
    };

    for (int i = 0; i < NUM_THREADS; ++i) {
        tuplestrint & arg = lstArg[i];
        lstTh.add_thread(new boost::thread(
            &processRequest, boost::get<0>(arg), boost::get<1>(arg)
        ));
    }

    lstTh.join_all();

    return 0;
}


================================================
FILE: cpp/cpp-boost/demo18a02-barrier.cpp
================================================
/*
BARRIERS AND LATCHES
Version A: Cyclic barriers
*/


#include <iostream>
#include <string>
#include <boost/tuple/tuple.hpp>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
using namespace std;



typedef boost::tuple<string,int> tuplestrint;

boost::barrier syncPoint(2); // participant count = 2



void processRequest(string userName, int waitTime) {
    boost::this_thread::sleep_for(boost::chrono::seconds(waitTime));

    cout << "Get request from " << userName << endl;
    syncPoint.count_down_and_wait();

    cout << "Process request for " << userName << endl;
    syncPoint.count_down_and_wait();

    cout << "Done " << userName << endl;
}



int main() {
    const int NUM_THREADS = 4;
    boost::thread_group lstTh;

    // tuple<userName, waitTime>
    tuplestrint lstArg[NUM_THREADS] = {
        tuplestrint("lorem", 1),
        tuplestrint("ipsum", 3),
        tuplestrint("dolor", 3),
        tuplestrint("amet", 10),
    };

    for (int i = 0; i < NUM_THREADS; ++i) {
        tuplestrint & arg = lstArg[i];
        lstTh.add_thread(new boost::thread(
            &processRequest, boost::get<0>(arg), boost::get<1>(arg)
        ));
    }

    // Thread with userName = "amet" shall be FREEZED

    lstTh.join_all();

    return 0;
}


================================================
FILE: cpp/cpp-boost/demo18a03-barrier.cpp
================================================
/*
BARRIERS AND LATCHES
Version A: Cyclic barriers
*/


#include <iostream>
#include <string>
#include <boost/tuple/tuple.hpp>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
using namespace std;



typedef boost::tuple<string,int> tuplestrint;

boost::barrier syncPointA(2);
boost::barrier syncPointB(2);



void processRequest(string userName, int waitTime) {
    boost::this_thread::sleep_for(boost::chrono::seconds(waitTime));

    cout << "Get request from " << userName << endl;
    syncPointA.count_down_and_wait();

    cout << "Process request for " << userName << endl;
    syncPointB.count_down_and_wait();

    cout << "Done " << userName << endl;
}



int main() {
    const int NUM_THREADS = 4;
    boost::thread_group lstTh;

    // tuple<userName, waitTime>
    tuplestrint lstArg[NUM_THREADS] = {
        tuplestrint("lorem", 1),
        tuplestrint("ipsum", 3),
        tuplestrint("dolor", 3),
        tuplestrint("amet", 10),
    };

    for (int i = 0; i < NUM_THREADS; ++i) {
        tuplestrint & arg = lstArg[i];
        lstTh.add_thread(new boost::thread(
            &processRequest, boost::get<0>(arg), boost::get<1>(arg)
        ));
    }

    lstTh.join_all();

    return 0;
}


================================================
FILE: cpp/cpp-boost/demo18b01-latch.cpp
================================================
/*
BARRIERS AND LATCHES
Version B: Count-down latches
*/


#include <iostream>
#include <string>
#include <boost/tuple/tuple.hpp>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include <boost/thread/latch.hpp>
using namespace std;



typedef boost::tuple<string,int> tuplestrint;

boost::latch syncPoint(3); // participant count = 3



void processRequest(string userName, int waitTime) {
    boost::this_thread::sleep_for(boost::chrono::seconds(waitTime));

    cout << "Get request from " << userName << endl;

    syncPoint.count_down();
    syncPoint.wait();
    // syncPoint.count_down_and_wait();

    cout << "Done " << userName << endl;
}



int main() {
    const int NUM_THREADS = 3;
    boost::thread_group lstTh;

    // tuple<userName, waitTime>
    tuplestrint lstArg[NUM_THREADS] = {
        tuplestrint("lorem", 1),
        tuplestrint("ipsum", 2),
        tuplestrint("dolor", 3)
    };

    for (int i = 0; i < NUM_THREADS; ++i) {
        tuplestrint & arg = lstArg[i];
        lstTh.add_thread(new boost::thread(
            &processRequest, boost::get<0>(arg), boost::get<1>(arg)
        ));
    }

    lstTh.join_all();

    return 0;
}


================================================
FILE: cpp/cpp-boost/demo18b02-latch.cpp
================================================
/*
BARRIERS AND LATCHES
Version B: Count-down latches

Main thread waits for 3 child threads to get enough data to progress.
*/


#include <iostream>
#include <string>
#include <boost/tuple/tuple.hpp>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include <boost/thread/latch.hpp>
using namespace std;



typedef boost::tuple<string,int> tuplestrint;

const int NUM_THREADS = 3;
boost::latch syncPoint(NUM_THREADS);



void doTask(string message, int waitTime) {
    boost::this_thread::sleep_for(boost::chrono::seconds(waitTime));

    cout << message << endl;
    syncPoint.count_down();

    boost::this_thread::sleep_for(boost::chrono::seconds(8));
    cout << "Cleanup" << endl;
}



int main() {
    boost::thread_group lstTh;

    // tuple<message, waitTime>
    tuplestrint lstArg[NUM_THREADS] = {
        tuplestrint("Send request to egg.net to get data", 6),
        tuplestrint("Send request to foo.org to get data", 2),
        tuplestrint("Send request to bar.com to get data", 4)
    };

    for (int i = 0; i < NUM_THREADS; ++i) {
        tuplestrint & arg = lstArg[i];

        lstTh.add_thread(new boost::thread(
            &doTask, boost::get<0>(arg), boost::get<1>(arg)
        ));
    }

    syncPoint.wait();
    cout << "\nNow we have enough data to progress to next step\n" << endl;

    lstTh.join_all();

    return 0;
}


================================================
FILE: cpp/cpp-boost/demo19a-read-write-lock.cpp
================================================
/*
READ-WRITE LOCKS
*/


#include <iostream>
#include <numeric>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include "mylib-random.hpp"
using namespace std;



volatile int resource = 0;
boost::shared_mutex rwmut;



void readFunc(int waitTime) {
    boost::this_thread::sleep_for(boost::chrono::seconds(waitTime));

    rwmut.lock_shared();

    cout << "read: " << resource << endl;

    rwmut.unlock_shared();
}



void writeFunc(int waitTime) {
    boost::this_thread::sleep_for(boost::chrono::seconds(waitTime));

    rwmut.lock();

    resource = mylib::RandInt::get(100);
    cout << "write: " << resource << endl;

    rwmut.unlock();
}



int main() {
    const int NUM_THREADS_READ = 10;
    const int NUM_THREADS_WRITE = 4;
    const int NUM_ARGS = 3;

    boost::thread_group lstThRead;
    boost::thread_group lstThWrite;
    int lstArg[NUM_ARGS];


    // INITIALIZE
    for (int i = 0; i < NUM_ARGS; ++i) {
        lstArg[i] = i;
    }


    // CREATE THREADS
    for (int i = 0; i < NUM_THREADS_READ; ++i) {
        int arg = lstArg[ mylib::RandInt::get(NUM_ARGS) ];

        lstThRead.add_thread(new boost::thread(
            &readFunc, arg
        ));
    }

    for (int i = 0; i < NUM_THREADS_WRITE; ++i) {
        int arg = lstArg[ mylib::RandInt::get(NUM_ARGS) ];

        lstThWrite.add_thread(new boost::thread(
            &writeFunc, arg
        ));
    }


    // JOIN THREADS
    lstThRead.join_all();
    lstThWrite.join_all();


    return 0;
}


================================================
FILE: cpp/cpp-boost/demo19b-read-write-lock.cpp
================================================
/*
READ-WRITE LOCKS
*/


#include <iostream>
#include <numeric>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include "mylib-random.hpp"
using namespace std;



volatile int resource = 0;
boost::shared_mutex rwmut;



void readFunc(int waitTime) {
    boost::this_thread::sleep_for(boost::chrono::seconds(waitTime));

    boost::shared_lock<boost::shared_mutex> lk(rwmut);

    cout << "read: " << resource << endl;

    // lk.unlock();
}



void writeFunc(int waitTime) {
    boost::this_thread::sleep_for(boost::chrono::seconds(waitTime));

    boost::lock_guard<boost::shared_mutex> lk(rwmut);
    // boost::unique_lock<boost::shared_mutex> lk(rwmut);

    resource = mylib::RandInt::get(100);
    cout << "write: " << resource << endl;

    // lk.unlock();
}



int main() {
    const int NUM_THREADS_READ = 10;
    const int NUM_THREADS_WRITE = 4;
    const int NUM_ARGS = 3;

    boost::thread_group lstThRead;
    boost::thread_group lstThWrite;
    int lstArg[NUM_ARGS];


    // INITIALIZE
    for (int i = 0; i < NUM_ARGS; ++i) {
        lstArg[i] = i;
    }


    // CREATE THREADS
    for (int i = 0; i < NUM_THREADS_READ; ++i) {
        int arg = lstArg[ mylib::RandInt::get(NUM_ARGS) ];

        lstThRead.add_thread(new boost::thread(
            &readFunc, arg
        ));
    }

    for (int i = 0; i < NUM_THREADS_WRITE; ++i) {
        int arg = lstArg[ mylib::RandInt::get(NUM_ARGS) ];

        lstThWrite.add_thread(new boost::thread(
            &writeFunc, arg
        ));
    }


    // JOIN THREADS
    lstThRead.join_all();
    lstThWrite.join_all();


    return 0;
}


================================================
FILE: cpp/cpp-boost/demo20a01-semaphore.cpp
================================================
/*
SEMAPHORES
Version A: Paper sheets and packages

Semaphores in C++ Boost threading are not supported by default.
So, I use mylib::Semaphore for this demonstration.
*/


#include <iostream>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include "mylib-semaphore.hpp"
using namespace std;



mylib::Semaphore semPackage(0);



void makeOneSheet() {
    for (int i = 0; i < 4; ++i) {
        cout << "Make 1 sheet" << endl;
        boost::this_thread::sleep_for(boost::chrono::seconds(1));
        semPackage.release();
    }
}



void combineOnePackage() {
    for (int i = 0; i < 4; ++i) {
        semPackage.acquire();
        semPackage.acquire();
        cout << "Combine 2 sheets into 1 package" << endl;
    }
}



int main() {
    boost::thread thMakeSheetA(&makeOneSheet);
    boost::thread thMakeSheetB(&makeOneSheet);
    boost::thread thCombinePackage(&combineOnePackage);

    thMakeSheetA.join();
    thMakeSheetB.join();
    thCombinePackage.join();

    return 0;
}


================================================
FILE: cpp/cpp-boost/demo20a02-semaphore.cpp
================================================
/*
SEMAPHORES
Version A: Paper sheets and packages

Semaphores in C++ Boost threading are not supported by default.
So, I use mylib::Semaphore for this demonstration.
*/


#include <iostream>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include "mylib-semaphore.hpp"
using namespace std;



mylib::Semaphore semPackage(0);
mylib::Semaphore semSheet(2);



void makeOneSheet() {
    for (int i = 0; i < 2; ++i) {
        semSheet.acquire();
        cout << "Make 1 sheet" << endl;
        semPackage.release();
    }
}



void combineOnePackage() {
    for (int i = 0; i < 2; ++i) {
        semPackage.acquire();
        semPackage.acquire();

        cout << "Combine 2 sheets into 1 package" << endl;
        boost::this_thread::sleep_for(boost::chrono::seconds(2));

        semSheet.release();
        semSheet.release();
    }
}



int main() {
    boost::thread thMakeSheetA(&makeOneSheet);
    boost::thread thMakeSheetB(&makeOneSheet);
    boost::thread thCombinePackage(&combineOnePackage);

    thMakeSheetA.join();
    thMakeSheetB.join();
    thCombinePackage.join();

    return 0;
}


================================================
FILE: cpp/cpp-boost/demo20a03-semaphore-deadlock.cpp
================================================
/*
SEMAPHORES
Version A: Paper sheets and packages

Semaphores in C++ Boost threading are not supported by default.
So, I use mylib::Semaphore for this demonstration.
*/


#include <iostream>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include "mylib-semaphore.hpp"
using namespace std;



mylib::Semaphore semPackage(0);
mylib::Semaphore semSheet(2);



void makeOneSheet() {
    for (int i = 0; i < 4; ++i) {
        semSheet.acquire();
        cout << "Make 1 sheet" << endl;
        semPackage.release();
    }
}



void combineOnePackage() {
    for (int i = 0; i < 4; ++i) {
        semPackage.acquire();
        semPackage.acquire();

        cout << "Combine 2 sheets into 1 package" << endl;
        boost::this_thread::sleep_for(boost::chrono::seconds(2));

        semSheet.release();
        // Missing one statement: semSheet.release() ==> deadlock
    }
}



int main() {
    boost::thread thMakeSheetA(&makeOneSheet);
    boost::thread thMakeSheetB(&makeOneSheet);
    boost::thread thCombinePackage(&combineOnePackage);

    thMakeSheetA.join();
    thMakeSheetB.join();
    thCombinePackage.join();

    return 0;
}


================================================
FILE: cpp/cpp-boost/demo20b-semaphore.cpp
================================================
/*
SEMAPHORES
Version B: Tires and chassis

Semaphores in C++ Boost threading are not supported by default.
So, I use mylib::Semaphore for this demonstration.
*/


#include <iostream>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include "mylib-semaphore.hpp"
using namespace std;



mylib::Semaphore semTire(4);
mylib::Semaphore semChassis(0);



void makeTire() {
    for (int i = 0; i < 8; ++i) {
        semTire.acquire();

        cout << "Make 1 tire" << endl;
        boost::this_thread::sleep_for(boost::chrono::seconds(1));

        semChassis.release();
    }
}



void makeChassis() {
    for (int i = 0; i < 4; ++i) {
        semChassis.acquire();
        semChassis.acquire();
        semChassis.acquire();
        semChassis.acquire();

        cout << "Make 1 chassis" << endl;
        boost::this_thread::sleep_for(boost::chrono::seconds(3));

        semTire.release();
        semTire.release();
        semTire.release();
        semTire.release();
    }
}



int main() {
    boost::thread thTireA(&makeTire);
    boost::thread thTireB(&makeTire);
    boost::thread thChassis(&makeChassis);

    thTireA.join();
    thTireB.join();
    thChassis.join();

    return 0;
}


================================================
FILE: cpp/cpp-boost/demo21a01-condition-variable.cpp
================================================
/*
CONDITION VARIABLES
*/


#include <iostream>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
using namespace std;



boost::mutex mut;
boost::condition_variable conditionVar;



void foo() {
    cout << "foo is waiting..." << endl;

    boost::unique_lock<boost::mutex> mutLock(mut);
    conditionVar.wait(mutLock);

    cout << "foo resumed" << endl;
}



void bar() {
    boost::this_thread::sleep_for(boost::chrono::seconds(3));
    conditionVar.notify_one();
}



int main() {
    boost::thread thFoo(&foo);
    boost::thread thBar(&bar);

    thFoo.join();
    thBar.join();

    return 0;
}


================================================
FILE: cpp/cpp-boost/demo21a02-condition-variable.cpp
================================================
/*
CONDITION VARIABLES
*/


#include <iostream>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
using namespace std;



boost::mutex mut;
boost::condition_variable conditionVar;

const int NUM_TH_FOO = 3;



void foo() {
    cout << "foo is waiting..." << endl;

    boost::unique_lock<boost::mutex> mutLock(mut);
    conditionVar.wait(mutLock);

    cout << "foo resumed" << endl;
}



void bar() {
    for (int i = 0; i < NUM_TH_FOO; ++i) {
        boost::this_thread::sleep_for(boost::chrono::seconds(2));
        conditionVar.notify_one();
    }
}



int main() {
    boost::thread_group lstThFoo;

    for (int i = 0; i < NUM_TH_FOO; ++i) {
        lstThFoo.add_thread(new boost::thread(&foo));
    }

    boost::thread thBar(&bar);

    lstThFoo.join_all();
    thBar.join();

    return 0;
}


================================================
FILE: cpp/cpp-boost/demo21a03-condition-variable.cpp
================================================
/*
CONDITION VARIABLES
*/


#include <iostream>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
using namespace std;



boost::mutex mut;
boost::condition_variable conditionVar;

const int NUM_TH_FOO = 3;



void foo() {
    cout << "foo is waiting..." << endl;

    boost::unique_lock<boost::mutex> mutLock(mut);
    conditionVar.wait(mutLock);

    cout << "foo resumed" << endl;
}



void bar() {
    boost::this_thread::sleep_for(boost::chrono::seconds(3));
    // Notify all waiting threads
    conditionVar.notify_all();
}



int main() {
    boost::thread_group lstThFoo;

    for (int i = 0; i < NUM_TH_FOO; ++i) {
        lstThFoo.add_thread(new boost::thread(&foo));
    }

    boost::thread thBar(&bar);

    lstThFoo.join_all();
    thBar.join();

    return 0;
}


================================================
FILE: cpp/cpp-boost/demo21b-condition-variable.cpp
================================================
/*
CONDITION VARIABLES
*/


#include <iostream>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
using namespace std;



boost::mutex mut;
boost::condition_variable conditionVar;

int counter = 0;

const int COUNT_HALT_01 = 3;
const int COUNT_HALT_02 = 6;
const int COUNT_DONE = 10;



// Write numbers 1-3 and 8-10 as permitted by egg()
void foo() {
    for (;;) {
        // Lock mutex and then wait for signal to relase mutex
        boost::unique_lock<boost::mutex> lk(mut);

        // Wait while egg() operates on counter,
        // Mutex unlocked if condition variable in egg() signaled
        conditionVar.wait(lk);

        ++counter;
        cout << "foo counter = " << counter << endl;

        if (counter >= COUNT_DONE) {
            return;
        }
    }
}



// Write numbers 4-7
void egg() {
    for (;;) {
        boost::unique_lock<boost::mutex> lk(mut);

        if (counter < COUNT_HALT_01 || counter > COUNT_HALT_02) {
            // Signal to free waiting thread by freeing the mutex
            // Note: foo() is now permitted to modify "counter"
            conditionVar.notify_one();
        }
        else {
            ++counter;
            cout << "egg counter = " << counter << endl;
        }

        if (counter >= COUNT_DONE) {
            return;
        }
    }
}



int main() {
    boost::thread thFoo(&foo);
    boost::thread thEgg(&egg);

    thFoo.join();
    thEgg.join();

    return 0;
}


================================================
FILE: cpp/cpp-boost/demo22a-blocking-queue.cpp
================================================
/*
BLOCKING QUEUES
Version A: A slow producer and a fast consumer

Blocking queues in C++ Boost threading are not supported by default.
So, I use mylib::BlockingQueue for this demonstration.
*/


#include <iostream>
#include <string>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include "mylib-blockingqueue.hpp"
using namespace std;
using namespace mylib;



void producer(BlockingQueue<string>* blkQueue) {
    boost::this_thread::sleep_for(boost::chrono::seconds(2));
    blkQueue->put("Alice");

    boost::this_thread::sleep_for(boost::chrono::seconds(2));
    blkQueue->put("likes");

    boost::this_thread::sleep_for(boost::chrono::seconds(2));
    blkQueue->put("singing");
}



void consumer(BlockingQueue<string>* blkQueue) {
    string data;

    for (int i = 0; i < 3; ++i) {
        cout << "\nWaiting for data..." << endl;
        data = blkQueue->take();
        cout << "    " << data << endl;
    }
}



int main() {
    BlockingQueue<string> blkQueue;

    boost::thread thProducer(&producer, &blkQueue);
    boost::thread thConsumer(&consumer, &blkQueue);

    thProducer.join();
    thConsumer.join();

    return 0;
}


================================================
FILE: cpp/cpp-boost/demo22b-blocking-queue.cpp
================================================
/*
BLOCKING QUEUES
Version B: A fast producer and a slow consumer

Blocking queues in C++ Boost threading are not supported by default.
So, I use mylib::BlockingQueue for this demonstration.
*/


#include <iostream>
#include <string>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include "mylib-blockingqueue.hpp"
using namespace std;
using namespace mylib;



void producer(BlockingQueue<string>* blkQueue) {
    blkQueue->put("Alice");
    blkQueue->put("likes");

    /*
    Due to reaching the maximum capacity = 2, when executing blkQueue->put("singing"),
    this thread is going to sleep until the queue removes an element.
    */

    blkQueue->put("singing");
}



void consumer(BlockingQueue<string>* blkQueue) {
    string data;
    boost::this_thread::sleep_for(boost::chrono::seconds(2));

    for (int i = 0; i < 3; ++i) {
        cout << "\nWaiting for data..." << endl;
        data = blkQueue->take();
        cout << "    " << data << endl;
    }
}



int main() {
    BlockingQueue<string> blkQueue(2); // blocking queue with capacity = 2

    boost::thread thProducer(&producer, &blkQueue);
    boost::thread thConsumer(&consumer, &blkQueue);

    thProducer.join();
    thConsumer.join();

    return 0;
}


================================================
FILE: cpp/cpp-boost/demo23a-thread-local.cpp
================================================
/*
THREAD-LOCAL STORAGE
Introduction
    The basic way to use thread-local storage
*/


#include <iostream>
#include <string>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
using namespace std;



boost::thread_specific_ptr<string> value;



void printLocalValue() {
    cout << (*value.get()) << endl;
}



void doTaskApple() {
    value.reset(new string("APPLE"));
    boost::this_thread::sleep_for(boost::chrono::seconds(2));
    printLocalValue();
}



void doTaskBanana() {
    value.reset(new string("BANANA"));
    boost::this_thread::sleep_for(boost::chrono::seconds(2));
    printLocalValue();
}



int main() {
    boost::thread thApple(&doTaskApple);
    boost::thread thBanana(&doTaskBanana);

    thApple.join();
    thBanana.join();

    return 0;
}


================================================
FILE: cpp/cpp-boost/demo23b-thread-local.cpp
================================================
/*
THREAD-LOCAL STORAGE
Avoiding synchronization using thread-local storage
*/


#include <iostream>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
using namespace std;



boost::thread_specific_ptr<int> counter;



void doTask(int t) {
    boost::this_thread::sleep_for(boost::chrono::seconds(1));
    counter.reset(new int(0));

    for (int i = 0; i < 1000; ++i)
        (*counter) += 1;

    cout << "Thread " << t << " gives counter = " << (*counter) << endl;
}



int main() {
    const int NUM_THREADS = 3;
    boost::thread_group lstTh;

    for (int i = 0; i < NUM_THREADS; ++i) {
        lstTh.add_thread(new boost::thread(&doTask, i));
    }

    lstTh.join_all();

    cout << endl;

    /*
    By using thread-local storage, each thread has its own counter.
    So, the counter in one thread is completely independent of each other.

    Thread-local storage helps us to AVOID SYNCHRONIZATION.
    */
    return 0;
}


================================================
FILE: cpp/cpp-boost/demo24-volatile.cpp
================================================
/*
THE VOLATILE KEYWORD
*/


#include <iostream>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
using namespace std;



volatile bool isRunning;



void doTask() {
    while (isRunning) {
        cout << "Running..." << endl;
        boost::this_thread::sleep_for(boost::chrono::seconds(2));
    }
}



int main() {
    isRunning = true;
    boost::thread th(&doTask);

    boost::this_thread::sleep_for(boost::chrono::seconds(6));
    isRunning = false;

    th.join();
    return 0;
}


================================================
FILE: cpp/cpp-boost/demo25a-atomic.cpp
================================================
/*
ATOMIC ACCESS
*/


#include <iostream>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
using namespace std;



volatile int counter = 0;



void doTask() {
    boost::this_thread::sleep_for(boost::chrono::seconds(1));
    counter += 1;
}



int main() {
    counter = 0;

    boost::thread_group lstTh;

    for (int i = 0; i < 1000; ++i) {
        lstTh.add_thread(new boost::thread(&doTask));
    }

    lstTh.join_all();

    // Unpredictable result
    cout << "counter = " << counter << endl;
    return 0;
}


================================================
FILE: cpp/cpp-boost/demo25b-atomic.cpp
================================================
/*
ATOMIC ACCESS
*/


#include <iostream>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
using namespace std;



// boost::atomic<int> counter;
boost::atomic_int32_t counter;



void doTask() {
    boost::this_thread::sleep_for(boost::chrono::seconds(1));
    counter += 1;
}



int main() {
    counter = 0;

    boost::thread_group lstTh;

    for (int i = 0; i < 1000; ++i) {
        lstTh.add_thread(new boost::thread(&doTask));
    }

    lstTh.join_all();

    // counter = 1000
    cout << "counter = " << counter << endl;
    return 0;
}


================================================
FILE: cpp/cpp-boost/demoex-async-future.cpp
================================================
/*
ASYNCHRONOUS PROGRAMMING WITH THE FUTURE
*/


#include <iostream>
#include <boost/ref.hpp>
#include <boost/move/move.hpp>
#include <boost/thread.hpp>



int doTaskA() {
    return 7;
}

int doTaskB() {
    return 8;
}

void doTaskC(boost::promise<int> & prom) {
    prom.set_value_at_thread_exit(9);
}



int main() {
    // future from a packaged_task (C++11)
    boost::packaged_task<int> task(&doTaskA);               // wrap the function
    boost::unique_future<int> fut1 = task.get_future();     // get a future
    boost::thread th(boost::move(task));                    // launch on a thread


    // future from an async()
    boost::unique_future<int> fut2 = boost::async(boost::launch::async, &doTaskB);


    // future from a promise
    boost::promise<int> prom;
    boost::unique_future<int> fut3 = prom.get_future();
    boost::thread(&doTaskC, boost::ref(prom)).detach();


    std::cout << "Waiting..." << std::endl;
    fut1.wait();
    fut2.wait();
    fut3.wait();
    th.join();


    std::cout << "Done!" << std::endl;

    std::cout << "Results are: "
              << fut1.get() << ' ' << fut2.get() << ' ' << fut3.get() << std::endl;


    return 0;
}


================================================
FILE: cpp/cpp-boost/exer01a-max-div.cpp
================================================
/*
MAXIMUM NUMBER OF DIVISORS
*/


#include <iostream>
#include "mylib-time.hpp"
using namespace std;



typedef boost::chrono::microseconds chrmicro;
typedef boost::chrono::steady_clock::time_point time_point;
typedef mylib::HiResClock hrclock;



int main() {
    const int RANGE_START = 1;
    const int RANGE_END = 100000;

    int resValue = 0;
    int resNumDiv = 0;  // number of divisors of result

    time_point tpStart = hrclock::now();


    for (int i = RANGE_START; i <= RANGE_END; ++i) {
        int numDiv = 0;

        for (int j = i / 2; j > 0; --j)
            if (i % j == 0)
                ++numDiv;

        if (resNumDiv < numDiv) {
            resNumDiv = numDiv;
            resValue = i;
        }
    }


    chrmicro timeElapsed = hrclock::getTimeSpan<chrmicro>(tpStart);

    cout << "The integer which has largest number of divisors is " << resValue << endl;
    cout << "The largest number of divisor is " << resNumDiv << endl;
    cout << "Time elapsed = " << (timeElapsed.count() / 1000000.0) << endl;

    return 0;
}


================================================
FILE: cpp/cpp-boost/exer01b-max-div.cpp
================================================
/*
MAXIMUM NUMBER OF DIVISORS
*/


#include <iostream>
#include <vector>
#include <algorithm>
#include <boost/thread.hpp>
#include "mylib-time.hpp"
using namespace std;



typedef boost::chrono::microseconds chrmicro;
typedef boost::chrono::steady_clock::time_point time_point;
typedef mylib::HiResClock hrclock;



struct WorkerArg {
    int iStart;
    int iEnd;

    WorkerArg(int iStart = 0, int iEnd = 0): iStart(iStart), iEnd(iEnd)
    {
    }
};



struct WorkerResult {
    int value;
    int numDiv;

    WorkerResult(int value = 0, int numDiv = 0): value(value), numDiv(numDiv)
    {
    }
};



void workerFunc(WorkerArg* arg, WorkerResult* res) {
    int resValue = 0;
    int resNumDiv = 0;

    for (int i = arg->iStart; i <= arg->iEnd; ++i) {
        int numDiv = 0;

        for (int j = i / 2; j > 0; --j)
            if (i % j == 0)
                ++numDiv;

        if (resNumDiv < numDiv) {
            resNumDiv = numDiv;
            resValue = i;
        }
    }

    (*res) = WorkerResult(resValue, resNumDiv);
}



void prepare(
    int rangeStart, int rangeEnd,
    int numThreads,
    vector<WorkerArg>& lstWorkerArg,
    vector<WorkerResult>& lstWorkerRes
) {
    lstWorkerArg.resize(numThreads);
    lstWorkerRes.resize(numThreads);

    int rangeA, rangeB, rangeBlock;

    rangeBlock = (rangeEnd - rangeStart + 1) / numThreads;
    rangeA = rangeStart;

    for (int i = 0; i < numThreads; ++i, rangeA += rangeBlock) {
        rangeB = rangeA + rangeBlock - 1;

        if (i == numThreads - 1)
            rangeB = rangeEnd;

        lstWorkerArg[i] = WorkerArg(rangeA, rangeB);
    }
}



int main() {
    const int RANGE_START = 1;
    const int RANGE_END = 100000;
    const int NUM_THREADS = 8;

    boost::thread_group lstTh;
    vector<WorkerArg> lstWorkerArg;
    vector<WorkerResult> lstWorkerRes;

    prepare(RANGE_START, RANGE_END, NUM_THREADS, lstWorkerArg, lstWorkerRes);

    time_point tpStart = hrclock::now();


    for (int i = 0; i < NUM_THREADS; ++i) {
        lstTh.add_thread(new boost::thread(&workerFunc, &lstWorkerArg[i], &lstWorkerRes[i]));
    }

    lstTh.join_all();


    WorkerResult finalRes = lstWorkerRes[0];

    for (int i = 1; i < lstWorkerRes.size(); ++i) {
        if (finalRes.numDiv < lstWorkerRes[i].numDiv) {
            finalRes = lstWorkerRes[i];
        }
    }


    chrmicro timeElapsed = hrclock::getTimeSpan<chrmicro>(tpStart);

    cout << "The integer which has largest number of divisors is " << finalRes.value << endl;
    cout << "The largest number of divisor is " << finalRes.numDiv << endl;
    cout << "Time elapsed = " << (timeElapsed.count() / 1000000.0) << endl;

    return 0;
}


================================================
FILE: cpp/cpp-boost/exer01c-max-div.cpp
================================================
/*
MAXIMUM NUMBER OF DIVISORS
*/


#include <iostream>
#include <vector>
#include <algorithm>
#include <boost/thread.hpp>
#include "mylib-time.hpp"
using namespace std;



typedef boost::chrono::microseconds chrmicro;
typedef boost::chrono::steady_clock::time_point time_point;
typedef mylib::HiResClock hrclock;



struct WorkerArg {
    int iStart;
    int iEnd;

    WorkerArg(int iStart = 0, int iEnd = 0): iStart(iStart), iEnd(iEnd)
    {
    }
};



class FinalResult {
public:
    int value;
    int numDiv;

private:
    boost::mutex mut;


public:
    FinalResult(): value(0), numDiv(0) { }


    void update(int value, int numDiv) {
        // Synchronize whole function
        boost::unique_lock<boost::mutex> lk(mut);

        if (this->numDiv < numDiv) {
            this->numDiv = numDiv;
            this->value = value;
        }
    }
};



void workerFunc(WorkerArg* arg, FinalResult* res) {
    int resValue = 0;
    int resNumDiv = 0;

    for (int i = arg->iStart; i <= arg->iEnd; ++i) {
        int numDiv = 0;

        for (int j = i / 2; j > 0; --j)
            if (i % j == 0)
                ++numDiv;

        if (resNumDiv < numDiv) {
            resNumDiv = numDiv;
            resValue = i;
        }
    }

    res->update(resValue, resNumDiv);
}



void prepare(
    int rangeStart, int rangeEnd,
    int numThreads,
    vector<WorkerArg>& lstWorkerArg
) {
    lstWorkerArg.resize(numThreads);

    int rangeA, rangeB, rangeBlock;

    rangeBlock = (rangeEnd - rangeStart + 1) / numThreads;
    rangeA = rangeStart;

    for (int i = 0; i < numThreads; ++i, rangeA += rangeBlock) {
        rangeB = rangeA + rangeBlock - 1;

        if (i == numThreads - 1)
            rangeB = rangeEnd;

        lstWorkerArg[i] = WorkerArg(rangeA, rangeB);
    }
}



int main() {
    const int RANGE_START = 1;
    const int RANGE_END = 100000;
    const int NUM_THREADS = 8;

    boost::thread_group lstTh;
    vector<WorkerArg> lstWorkerArg;

    FinalResult finalRes;

    prepare(RANGE_START, RANGE_END, NUM_THREADS, lstWorkerArg);

    time_point tpStart = hrclock::now();


    for (int i = 0; i < NUM_THREADS; ++i) {
        lstTh.add_thread(new boost::thread(&workerFunc, &lstWorkerArg[i], &finalRes));
    }

    lstTh.join_all();


    chrmicro timeElapsed = hrclock::getTimeSpan<chrmicro>(tpStart);

    cout << "The integer which has largest number of divisors is " << finalRes.value << endl;
    cout << "The largest number of divisor is " << finalRes.numDiv << endl;
    cout << "Time elapsed = " << (timeElapsed.count() / 1000000.0) << endl;

    return 0;
}


================================================
FILE: cpp/cpp-boost/exer02a01-producer-consumer.cpp
================================================
/*
THE PRODUCER-CONSUMER PROBLEM

SOLUTION TYPE A: USING BLOCKING QUEUES
    Version A01: 1 slow producer, 1 fast consumer
*/


#include <iostream>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include "mylib-blockingqueue.hpp"
using namespace std;
using namespace mylib;



void producer(BlockingQueue<int>* blkq) {
    int i = 1;

    for (;; ++i) {
        blkq->put(i);
        boost::this_thread::sleep_for(boost::chrono::seconds(1));
    }
}



void consumer(BlockingQueue<int>* blkq) {
    int data = 0;

    for (;;) {
        data = blkq->take();
        cout << "Consumer " << data << endl;
    }
}



int main() {
    BlockingQueue<int> blkq;

    boost::thread thProducer(&producer, &blkq);
    boost::thread thConsumer(&consumer, &blkq);

    thProducer.join();
    thConsumer.join();

    return 0;
}


================================================
FILE: cpp/cpp-boost/exer02a02-producer-consumer.cpp
================================================
/*
THE PRODUCER-CONSUMER PROBLEM

SOLUTION TYPE A: USING BLOCKING QUEUES
    Version A02: 2 slow producers, 1 fast consumer
*/


#include <iostream>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include "mylib-blockingqueue.hpp"
using namespace std;
using namespace mylib;



void producer(BlockingQueue<int>* blkq) {
    int i = 1;

    for (;; ++i) {
        blkq->put(i);
        boost::this_thread::sleep_for(boost::chrono::seconds(1));
    }
}



void consumer(BlockingQueue<int>* blkq) {
    int data = 0;

    for (;;) {
        data = blkq->take();
        cout << "Consumer " << data << endl;
    }
}



int main() {
    BlockingQueue<int> blkq;

    boost::thread thProducerA(&producer, &blkq);
    boost::thread thProducerB(&producer, &blkq);
    boost::thread thConsumer(&consumer, &blkq);

    thProducerA.join();
    thProducerB.join();
    thConsumer.join();

    return 0;
}


================================================
FILE: cpp/cpp-boost/exer02a03-producer-consumer.cpp
================================================
/*
THE PRODUCER-CONSUMER PROBLEM

SOLUTION TYPE A: USING BLOCKING QUEUES
    Version A03: 1 slow producer, 2 fast consumers
*/


#include <iostream>
#include <string>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include "mylib-blockingqueue.hpp"
using namespace std;
using namespace mylib;



void producer(BlockingQueue<int>* blkq) {
    int i = 1;

    for (;; ++i) {
        blkq->put(i);
        boost::this_thread::sleep_for(boost::chrono::seconds(1));
    }
}



void consumer(string name, BlockingQueue<int>* blkq) {
    int data = 0;

    for (;;) {
        data = blkq->take();
        cout << "Consumer " << name << ": " << data << endl;
    }
}



int main() {
    BlockingQueue<int> blkq;

    boost::thread thProducer(&producer, &blkq);
    boost::thread thConsumerFoo(&consumer, "foo", &blkq);
    boost::thread thConsumerBar(&consumer, "bar", &blkq);

    thProducer.join();
    thConsumerFoo.join();
    thConsumerBar.join();

    return 0;
}


================================================
FILE: cpp/cpp-boost/exer02a04-producer-consumer.cpp
================================================
/*
THE PRODUCER-CONSUMER PROBLEM

SOLUTION TYPE A: USING BLOCKING QUEUES
    Version A04: Multiple fast producers, multiple slow consumers
*/


#include <iostream>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include "mylib-blockingqueue.hpp"
using namespace std;
using namespace mylib;



void producer(BlockingQueue<int>* blkq, int startValue) {
    int i = 1;

    for (;; ++i) {
        blkq->put(i + startValue);
    }
}



void consumer(BlockingQueue<int>* blkq) {
    int data = 0;

    for (;;) {
        data = blkq->take();
        cout << "Consumer " << data << endl;
        boost::this_thread::sleep_for(boost::chrono::seconds(1));
    }
}



int main() {
    BlockingQueue<int> blkq(5);


    const int NUM_PRODUCERS = 3;
    const int NUM_CONSUMERS = 2;

    boost::thread_group lstThProducer;
    boost::thread_group lstThConsumer;


    // CREATE THREADS
    for (int i = 0; i < NUM_PRODUCERS; ++i) {
        lstThProducer.add_thread(new boost::thread(&producer, &blkq, i * 1000));
    }

    for (int i = 0; i < NUM_CONSUMERS; ++i) {
        lstThConsumer.add_thread(new boost::thread(&consumer, &blkq));
    }


    // JOIN THREADS
    lstThProducer.join_all();
    lstThConsumer.join_all();


    return 0;
}


================================================
FILE: cpp/cpp-boost/exer02b01-producer-consumer.cpp
================================================
/*
THE PRODUCER-CONSUMER PROBLEM

SOLUTION TYPE B: USING SEMAPHORES
    Version B01: 1 slow producer, 1 fast consumer
*/


#include <iostream>
#include <queue>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include "mylib-semaphore.hpp"
using namespace std;



void producer(
    mylib::Semaphore* semFill,
    mylib::Semaphore* semEmpty,
    queue<int>* q
) {
    int i = 1;

    for (;; ++i) {
        semEmpty->acquire();

        q->push(i);
        boost::this_thread::sleep_for(boost::chrono::seconds(1));

        semFill->release();
    }
}



void consumer(
    mylib::Semaphore* semFill,
    mylib::Semaphore* semEmpty,
    queue<int>* q
) {
    int data = 0;

    for (;;) {
        semFill->acquire();

        data = q->front();
        q->pop();

        cout << "Consumer " << data << endl;

        semEmpty->release();
    }
}



int main() {
    mylib::Semaphore semFill(0);   // item produced
    mylib::Semaphore semEmpty(1);  // remaining space in queue

    queue<int> q;

    boost::thread thProducer(&producer, &semFill, &semEmpty, &q);
    boost::thread thConsumer(&consumer, &semFill, &semEmpty, &q);

    thProducer.join();
    thConsumer.join();

    return 0;
}


================================================
FILE: cpp/cpp-boost/exer02b02-producer-consumer.cpp
================================================
/*
THE PRODUCER-CONSUMER PROBLEM

SOLUTION TYPE B: USING SEMAPHORES
    Version B02: 2 slow producers, 1 fast consumer
*/


#include <iostream>
#include <queue>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include "mylib-semaphore.hpp"
using namespace std;



void producer(
    mylib::Semaphore* semFill,
    mylib::Semaphore* semEmpty,
    queue<int>* q,
    int startValue
) {
    int i = 1;

    for (;; ++i) {
        semEmpty->acquire();

        q->push(i + startValue);
        boost::this_thread::sleep_for(boost::chrono::seconds(1));

        semFill->release();
    }
}



void consumer(
    mylib::Semaphore* semFill,
    mylib::Semaphore* semEmpty,
    queue<int>* q
) {
    int data = 0;

    for (;;) {
        semFill->acquire();

        data = q->front();
        q->pop();

        cout << "Consumer " << data << endl;

        semEmpty->release();
    }
}



int main() {
    mylib::Semaphore semFill(0);   // item produced
    mylib::Semaphore semEmpty(1);  // remaining space in queue

    queue<int> q;

    boost::thread thProducerA(&producer, &semFill, &semEmpty, &q, 0);
    boost::thread thProducerB(&producer, &semFill, &semEmpty, &q, 1000);
    boost::thread thConsumer(&consumer, &semFill, &semEmpty, &q);

    thProducerA.join();
    thProducerB.join();
    thConsumer.join();

    return 0;
}


================================================
FILE: cpp/cpp-boost/exer02b03-producer-consumer.cpp
================================================
/*
THE PRODUCER-CONSUMER PROBLEM

SOLUTION TYPE B: USING SEMAPHORES
    Version B03: 2 fast producers, 1 slow consumer
*/


#include <iostream>
#include <queue>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include "mylib-semaphore.hpp"
using namespace std;



void producer(
    mylib::Semaphore* semFill,
    mylib::Semaphore* semEmpty,
    queue<int>* q,
    int startValue
) {
    int i = 1;

    for (;; ++i) {
        semEmpty->acquire();
        q->push(i + startValue);
        semFill->release();
    }
}



void consumer(
    mylib::Semaphore* semFill,
    mylib::Semaphore* semEmpty,
    queue<int>* q
) {
    int data = 0;

    for (;;) {
        semFill->acquire();

        data = q->front();
        q->pop();

        cout << "Consumer " << data << endl;
        boost::this_thread::sleep_for(boost::chrono::seconds(1));

        semEmpty->release();
    }
}



int main() {
    mylib::Semaphore semFill(0);   // item produced
    mylib::Semaphore semEmpty(1);  // remaining space in queue

    queue<int> q;

    boost::thread thProducerA(&producer, &semFill, &semEmpty, &q, 0);
    boost::thread thProducerB(&producer, &semFill, &semEmpty, &q, 1000);
    boost::thread thConsumer(&consumer, &semFill, &semEmpty, &q);

    thProducerA.join();
    thProducerB.join();
    thConsumer.join();

    return 0;
}


================================================
FILE: cpp/cpp-boost/exer02b04-producer-consumer.cpp
================================================
/*
THE PRODUCER-CONSUMER PROBLEM

SOLUTION TYPE B: USING SEMAPHORES
    Version B04: Multiple fast producers, multiple slow consumers
*/


#include <iostream>
#include <queue>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include "mylib-semaphore.hpp"
using namespace std;



void producer(
    mylib::Semaphore* semFill,
    mylib::Semaphore* semEmpty,
    queue<int>* q,
    int startValue
) {
    int i = 1;

    for (;; ++i) {
        semEmpty->acquire();
        q->push(i + startValue);
        semFill->release();
    }
}



void consumer(
    mylib::Semaphore* semFill,
    mylib::Semaphore* semEmpty,
    queue<int>* q
) {
    int data = 0;

    for (;;) {
        semFill->acquire();

        data = q->front();
        q->pop();

        cout << "Consumer " << data << endl;
        boost::this_thread::sleep_for(boost::chrono::seconds(1));

        semEmpty->release();
    }
}



int main() {
    mylib::Semaphore semFill(0);   // item produced
    mylib::Semaphore semEmpty(1);  // remaining space in queue

    queue<int> q;


    const int NUM_PRODUCERS = 3;
    const int NUM_CONSUMERS = 2;

    boost::thread_group lstThProducer;
    boost::thread_group lstThConsumer;


    // CREATE THREADS
    for (int i = 0; i < NUM_PRODUCERS; ++i) {
        lstThProducer.add_thread(new boost::thread(
            &producer, &semFill, &semEmpty, &q, i * 1000
        ));
    }

    for (int i = 0; i < NUM_CONSUMERS; ++i) {
        lstThConsumer.add_thread(new boost::thread(
            &consumer, &semFill, &semEmpty, &q
        ));
    }


    // JOIN THREADS
    lstThProducer.join_all();
    lstThConsumer.join_all();


    return 0;
}


================================================
FILE: cpp/cpp-boost/exer02c-producer-consumer.cpp
================================================
/*
THE PRODUCER-CONSUMER PROBLEM

SOLUTION TYPE C: USING CONDITION VARIABLES & MONITORS
    Multiple fast producers, multiple slow consumers
*/


#include <iostream>
#include <queue>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
using namespace std;



template <typename T>
class Monitor {
private:
    std::queue<T>* q;
    int maxQueueSize;

    boost::condition_variable condFull;
    boost::condition_variable condEmpty;
    boost::mutex mut;


public:
    Monitor() : q(0), maxQueueSize(0) { }


private:
    Monitor(const Monitor& other) { }
    void operator=(const Monitor& other) { }


public:
    void init(int maxQueueSize, std::queue<T>* q) {
        this->q = q;
        this->maxQueueSize = maxQueueSize;
    }


    void add(const T& item) {
        boost::unique_lock<boost::mutex> mutLock(mut);

        while (q->size() == maxQueueSize) {
            condFull.wait(mutLock);
        }

        q->push(item);

        if (q->size() == 1) {
            condEmpty.notify_one();
        }

        // mutLock.unlock();
    }


    T remove() {
        boost::unique_lock<boost::mutex> mutLock(mut);

        while (q->size() == 0) {
            condEmpty.wait(mutLock);
        }

        T item = q->front();
        q->pop();

        if (q->size() == maxQueueSize - 1) {
            condFull.notify_one();
        }

        // mutLock.unlock();

        return item;
    }
};



template <typename T>
void producer(Monitor<T>* monitor, int startValue) {
    T i = 1;

    for (;; ++i) {
        monitor->add(i + startValue);
    }
}



template <typename T>
void consumer(Monitor<T>* monitor) {
    T data;

    for (;;) {
        data = monitor->remove();
        cout << "Consumer " << data << endl;
        boost::this_thread::sleep_for(boost::chrono::seconds(1));
    }
}



int main() {
    Monitor<int> monitor;
    queue<int> q;

    const int MAX_QUEUE_SIZE = 6;
    const int NUM_PRODUCERS = 3;
    const int NUM_CONSUMERS = 2;

    boost::thread_group lstThProducer;
    boost::thread_group lstThConsumer;


    // PREPARE ARGUMENTS
    monitor.init(MAX_QUEUE_SIZE, &q);


    // CREATE THREADS
    for (int i = 0; i < NUM_PRODUCERS; ++i) {
        lstThProducer.add_thread(new boost::thread(&producer<int>, &monitor, i * 1000));
    }

    for (int i = 0; i < NUM_CONSUMERS; ++i) {
        lstThConsumer.add_thread(new boost::thread(&consumer<int>, &monitor));
    }


    // JOIN THREADS
    lstThProducer.join_all();
    lstThConsumer.join_all();


    return 0;
}


================================================
FILE: cpp/cpp-boost/exer03a-readers-writers.cpp
================================================
/*
THE READERS-WRITERS PROBLEM
Solution for the first readers-writers problem
*/


#include <iostream>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include "mylib-random.hpp"
using namespace std;



struct GlobalData {
    volatile int resource;
    int readerCount;

    boost::mutex mutResource;
    boost::mutex mutReaderCount;
};



void doTaskWriter(GlobalData* g, int delayTime) {
    boost::this_thread::sleep_for(boost::chrono::seconds(delayTime));

    g->mutResource.lock();

    g->resource = mylib::RandInt::get(100);
    cout << "Write " << g->resource << endl;

    g->mutResource.unlock();
}



void doTaskReader(GlobalData* g, int delayTime) {
    boost::this_thread::sleep_for(boost::chrono::seconds(delayTime));


    // Increase reader count
    g->mutReaderCount.lock();
    g->readerCount += 1;

    if (1 == g->readerCount)
        g->mutResource.lock();

    g->mutReaderCount.unlock();


    // Do the reading
    cout << "Read " << g->resource << endl;


    // Decrease reader count
    g->mutReaderCount.lock();
    g->readerCount -= 1;

    if (0 == g->readerCount)
        g->mutResource.unlock();

    g->mutReaderCount.unlock();
}



int main() {
    GlobalData globalData;
    globalData.resource = 0;
    globalData.readerCount = 0;


    const int NUM_READERS = 8;
    const int NUM_WRITERS = 6;

    boost::thread_group lstThReader;
    boost::thread_group lstThWriter;


    // CREATE THREADS
    for (int i = 0; i < NUM_READERS; ++i) {
        lstThReader.add_thread(new boost::thread(
            &doTaskReader, &globalData, mylib::RandInt::get(3)
        ));
    }

    for (int i = 0; i < NUM_WRITERS; ++i) {
        lstThWriter.add_thread(new boost::thread(
            &doTaskWriter, &globalData, mylib::RandInt::get(3)
        ));
    }


    // JOIN THREADS
    lstThReader.join_all();
    lstThWriter.join_all();


    return 0;
}


================================================
FILE: cpp/cpp-boost/exer03b-readers-writers.cpp
================================================
/*
THE READERS-WRITERS PROBLEM
Solution for the third readers-writers problem
*/


#include <iostream>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include "mylib-random.hpp"
using namespace std;



struct GlobalData {
    volatile int resource;
    int readerCount;

    boost::mutex mutResource;
    boost::mutex mutReaderCount;

    boost::mutex mutServiceQueue;
};



void doTaskWriter(GlobalData* g, int delayTime) {
    boost::this_thread::sleep_for(boost::chrono::seconds(delayTime));

    g->mutServiceQueue.lock();

    g->mutResource.lock();

    g->mutServiceQueue.unlock();

    g->resource = mylib::RandInt::get(100);
    cout << "Write " << g->resource << endl;

    g->mutResource.unlock();
}



void doTaskReader(GlobalData* g, int delayTime) {
    boost::this_thread::sleep_for(boost::chrono::seconds(delayTime));


    g->mutServiceQueue.lock();


    // Increase reader count
    g->mutReaderCount.lock();
    g->readerCount += 1;

    if (1 == g->readerCount)
        g->mutResource.lock();

    g->mutReaderCount.unlock();


    g->mutServiceQueue.unlock();


    // Do the reading
    cout << "Read " << g->resource << endl;


    // Decrease reader count
    g->mutReaderCount.lock();
    g->readerCount -= 1;

    if (0 == g->readerCount)
        g->mutResource.unlock();

    g->mutReaderCount.unlock();
}



int main() {
    GlobalData globalData;
    globalData.resource = 0;
    globalData.readerCount = 0;


    const int NUM_READERS = 8;
    const int NUM_WRITERS = 6;

    boost::thread_group lstThReader;
    boost::thread_group lstThWriter;


    // CREATE THREADS
    for (int i = 0; i < NUM_READERS; ++i) {
        lstThReader.add_thread(new boost::thread(
            &doTaskReader, &globalData, mylib::RandInt::get(3)
        ));
    }

    for (int i = 0; i < NUM_WRITERS; ++i) {
        lstThWriter.add_thread(new boost::thread(
            &doTaskWriter, &globalData, mylib::RandInt::get(3)
        ));
    }


    // JOIN THREADS
    lstThReader.join_all();
    lstThWriter.join_all();


    return 0;
}


================================================
FILE: cpp/cpp-boost/exer04-dining-philosophers.cpp
================================================
/*
THE DINING PHILOSOPHERS PROBLEM
*/


#include <iostream>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
using namespace std;



void doTaskPhilosopher(boost::mutex chopstick[], int numPhilo, int idPhilo) {
    int n = numPhilo;
    int i = idPhilo;

    boost::this_thread::sleep_for(boost::chrono::seconds(1));

    chopstick[i].lock();
    chopstick[(i + 1) % n].lock();

    cout << "Philosopher #" << i << " is eating the rice" << endl;

    chopstick[(i + 1) % n].unlock();
    chopstick[i].unlock();
}



void doTaskPhilosopherUsingSyncBlock(boost::mutex chopstick[], int numPhilo, int idPhilo) {
    int n = numPhilo;
    int i = idPhilo;

    boost::this_thread::sleep_for(boost::chrono::seconds(1));

    {
        boost::unique_lock<boost::mutex> ( chopstick[i] );
        boost::unique_lock<boost::mutex> ( chopstick[(i + 1) % n] );
        cout << "Philosopher #" << i << " is eating the rice" << endl;
    }
}



int main() {
    const int NUM_PHILOSOPHERS = 5;

    boost::mutex chopstick[NUM_PHILOSOPHERS];
    boost::thread_group lstTh;

    // CREATE THREADS
    for (int i = 0; i < NUM_PHILOSOPHERS; ++i) {
        lstTh.add_thread(new boost::thread(
            &doTaskPhilosopher, chopstick, NUM_PHILOSOPHERS, i
        ));
    }

    // JOIN THREADS
    lstTh.join_all();

    return 0;
}


================================================
FILE: cpp/cpp-boost/exer05-util.hpp
================================================
#ifndef _EXER05_UTIL_HPP_
#define _EXER05_UTIL_HPP_



void getScalarProduct(double const* u, double const* v, int sizeVector, double* res) {
    double sum = 0;

    for (int i = sizeVector - 1; i >= 0; --i) {
        sum += u[i] * v[i];
    }

    (*res) = sum;
}



#endif // _EXER05_UTIL_HPP_


================================================
FILE: cpp/cpp-boost/exer05a-product-matrix-vector.cpp
================================================
/*
MATRIX-VECTOR MULTIPLICATION
*/


#include <iostream>
#include <vector>
#include <boost/assign/std/vector.hpp>
#include <boost/thread.hpp>
#include "exer05-util.hpp"
using namespace std;
using namespace boost::assign;



typedef std::vector<double> vectord;
typedef std::vector<vectord> matrix;



void getProduct(const matrix& mat, const vectord& vec, vectord& result) {
    // Assume that size of mat and vec are both eligible
    int sizeRowMat = mat.size();
    int sizeColMat = mat[0].size();
    int sizeVec = vec.size();

    result.clear();
    result.resize(sizeRowMat, 0);

    boost::thread_group lstTh;

    for (int i = 0; i < sizeRowMat; ++i) {
        lstTh.add_thread(new boost::thread(
            &getScalarProduct, mat[i].data(), vec.data(), sizeVec, &result[i]
        ));
    }

    lstTh.join_all();
}



int main() {
    matrix A;

    {
        vectord row1, row2, row3;
        row1 += 1, 2, 3;
        row2 += 4, 5, 6;
        row3 += 7, 8, 9;
        A += row1, row2, row3;
    }

    vectord b;
    b += 3, -1, 0;

    vectord result;
    getProduct(A, b, result);

    for (int i = 0; i < result.size(); ++i) {
        cout << result[i] << endl;
    }

    return 0;
}


================================================
FILE: cpp/cpp-boost/exer05b-product-matrix-matrix.cpp
================================================
/*
MATRIX-MATRIX MULTIPLICATION (DOT PRODUCT)
*/


#include <iostream>
#include <vector>
#include <boost/assign/std/vector.hpp>
#include <boost/thread.hpp>
#include "exer05-util.hpp"
using namespace std;
using namespace boost::assign;



typedef std::vector<double> vectord;
typedef std::vector<vectord> matrix;



void getTransposeMatrix(const matrix& input, matrix& output) {
    int numRow = input.size();
    int numCol = input[0].size();

    output.clear();
    output.assign(numCol, vectord(numRow, 0));

    for (int i = 0; i < numRow; ++i)
        for (int j = 0; j < numCol; ++j)
            output[j][i] = input[i][j];
}



void displayMatrix(const matrix& mat) {
    int numRow = mat.size();
    int numCol = mat[0].size();

    for (int i = 0; i < numRow; ++i) {
        for (int j = 0; j < numCol; ++j)
            cout << "\t" << mat[i][j];

        cout << endl;
    }
}



void getProduct(const matrix& matA, const matrix& matB, matrix& result) {
    // Assume that size of matA and matB are both eligible
    int sizeRowA = matA.size();
    int sizeColA = matA[0].size();
    int sizeColB = matB[0].size();
    int sizeTotal = sizeRowA * sizeColB;

    result.clear();
    result.assign(sizeRowA, vectord(sizeColB, 0));

    matrix matBT;
    getTransposeMatrix(matB, matBT);

    boost::thread_group lstTh;

    for (int i = 0; i < sizeRowA; ++i) {
        for (int j = 0; j < sizeColB; ++j) {
            int sizeVector = sizeColA;

            lstTh.add_thread(new boost::thread(
                &getScalarProduct, matA[i].data(), matBT[j].data(), sizeVector, &result[i][j]
            ));
        }
    }

    lstTh.join_all();
}



int main() {
    matrix A, B;

    {
        vectord row1, row2;
        row1 += 1, 3, 5;
        row2 += 2, 4, 6;
        A += row1, row2;
    }

    {
        vectord row1, row2, row3;
        row1 += 1, 0, 1, 0;
        row2 += 0, 1, 0, 1;
        row3 += 1, 0, 0, -2;
        B += row1, row2, row3;
    }

    matrix result;
    getProduct(A, B, result);

    displayMatrix(result);

    return 0;
}


================================================
FILE: cpp/cpp-boost/exer06a-blocking-queue.cpp
================================================
/*
BLOCKING QUEUE IMPLEMENTATION
Version A: Synchronous queues
*/


#include <iostream>
#include <string>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include "mylib-semaphore.hpp"
using namespace std;



template <typename T>
class SynchronousQueue {

private:
    mylib::Semaphore semPut;
    mylib::Semaphore semTake;
    T element;


public:
    SynchronousQueue() : semPut(1), semTake(0) { }


    void put(const T& value) {
        semPut.acquire();
        element = value;
        semTake.release();
    }


    T take() {
        semTake.acquire();
        T result = element;
        semPut.release();
        return result;
    }

};



void producer(SynchronousQueue<std::string>* syncQueue) {
    std::string arr[] = { "lorem", "ipsum", "dolor" };

    for (int i = 0; i < 3; ++i) {
        std::string& data = arr[i];
        cout << "Producer: " << data << endl;
        syncQueue->put(data);
        cout << "Producer: " << data << "\t\t\t[done]" << endl;
    }
}



void consumer(SynchronousQueue<std::string>* syncQueue) {
    std::string data;
    boost::this_thread::sleep_for(boost::chrono::seconds(5));

    for (int i = 0; i < 3; ++i) {
        data = syncQueue->take();
        cout << "\tConsumer: " << data << endl;
    }
}



int main() {
    SynchronousQueue<std::string> syncQueue;

    boost::thread thProducer(&producer, &syncQueue);
    boost::thread thConsumer(&consumer, &syncQueue);

    thProducer.join();
    thConsumer.join();

    return 0;
}


================================================
FILE: cpp/cpp-boost/exer06b01-blocking-queue.cpp
================================================
/*
BLOCKING QUEUE IMPLEMENTATION
Version B01: General blocking queues
             Underlying mechanism: Semaphores
*/


#include <iostream>
#include <queue>
#include <string>
#include <stdexcept>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include "mylib-semaphore.hpp"
using namespace std;



template <typename T>
class BlockingQueue {

private:
    int capacity;

    mylib::Semaphore semRemain;
    mylib::Semaphore semFill;
    boost::mutex mut;

    std::queue<T> q;


public:
    BlockingQueue(int capacity) : capacity(capacity), semRemain(capacity), semFill(0) {
        if (this->capacity <= 0)
            throw std::invalid_argument("capacity must be a positive integer");
    }


    void put(const T& value) {
        semRemain.acquire();

        {
            boost::unique_lock<boost::mutex> lk(mut);
            q.push(value);
        }

        semFill.release();
    }


    T take() {
        T result;
        semFill.acquire();

        {
            boost::unique_lock<boost::mutex> lk(mut);
            result = q.front();
            q.pop();
        }

        semRemain.release();
        return result;
    }

};



void producer(BlockingQueue<std::string>* blkQueue) {
    std::string arr[] = { "nice", "to", "meet", "you" };

    for (int i = 0; i < 4; ++i) {
        std::string& data = arr[i];
        cout << "Producer: " << data << endl;
        blkQueue->put(data);
        cout << "Producer: " << data << "\t\t\t[done]" << endl;
    }
}



void consumer(BlockingQueue<std::string>* blkQueue) {
    std::string data;
    boost::this_thread::sleep_for(boost::chrono::seconds(5));

    for (int i = 0; i < 4; ++i) {
        data = blkQueue->take();
        cout << "\tConsumer: " << data << endl;

        if (0 == i)
            boost::this_thread::sleep_for(boost::chrono::seconds(5));
    }
}



int main() {
    BlockingQueue<std::string> blkQueue(2); // capacity = 2

    boost::thread thProducer(&producer, &blkQueue);
    boost::thread thConsumer(&consumer, &blkQueue);

    thProducer.join();
    thConsumer.join();

    return 0;
}


================================================
FILE: cpp/cpp-boost/exer06b02-blocking-queue.cpp
================================================
/*
BLOCKING QUEUE IMPLEMENTATION
Version B02: General blocking queues
             Underlying mechanism: Condition variables
*/


#include <iostream>
#include <queue>
#include <string>
#include <stdexcept>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
using namespace std;



template <typename T>
class BlockingQueue {

private:
    boost::condition_variable condEmpty;
    boost::condition_variable condFull;
    boost::mutex mut;

    int capacity;
    std::queue<T> q;


public:
    BlockingQueue(int capacity) {
        if (capacity <= 0)
            throw std::invalid_argument("capacity must be a positive integer");

        this->capacity = capacity;
    }


    void put(const T& value) {
        {
            boost::unique_lock<boost::mutex> lk(mut);

            while ((int)q.size() >= capacity) {
                // Queue is full, must wait for 'take'
                condFull.wait(lk);
            }

            q.push(value);
        }

        condEmpty.notify_one();
    }


    T take() {
        T result;

        {
            boost::unique_lock<boost::mutex> lk(mut);

            while (q.empty()) {
                // Queue is empty, must wait for 'put'
                condEmpty.wait(lk);
            }

            result = q.front();
            q.pop();
        }

        condFull.notify_one();
        return result;
    }

};



void producer(BlockingQueue<std::string>* blkQueue) {
    std::string arr[] = { "nice", "to", "meet", "you" };

    for (int i = 0; i < 4; ++i) {
        std::string& data = arr[i];
        cout << "Producer: " << data << endl;
        blkQueue->put(data);
        cout << "Producer: " << data << "\t\t\t[done]" << endl;
    }
}



void consumer(BlockingQueue<std::string>* blkQueue) {
    std::string data;
    boost::this_thread::sleep_for(boost::chrono::seconds(5));

    for (int i = 0; i < 4; ++i) {
        data = blkQueue->take();
        cout << "\tConsumer: " << data << endl;

        if (0 == i)
            boost::this_thread::sleep_for(boost::chrono::seconds(5));
    }
}



int main() {
    BlockingQueue<std::string> blkQueue(2); // capacity = 2

    boost::thread thProducer(&producer, &blkQueue);
    boost::thread thConsumer(&consumer, &blkQueue);

    thProducer.join();
    thConsumer.join();

    return 0;
}


================================================
FILE: cpp/cpp-boost/exer07a-data-server.cpp
================================================
/*
THE DATA SERVER PROBLEM
Version A: Solving the problem using a condition variable
*/


#include <iostream>
#include <string>
#include <vector>
#include <boost/ref.hpp>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
using namespace std;



#define sleepsec(secs) \
    do { boost::this_thread::sleep_for(boost::chrono::seconds(secs)); } while (0)



struct Counter {
    int value;
    boost::mutex mut;
    boost::condition_variable cond;
    Counter(int value) : value(value) { }
};



void checkAuthUser() {
    cout << "[   Auth   ] Start" << endl;
    // Send request to authenticator, check permissions, encrypt, decrypt...
    sleepsec(20);
    cout << "[   Auth   ] Done" << endl;
}



void processFiles(const vector<string>& lstFileName, Counter& counter) {
    for (size_t i = 0; i < lstFileName.size(); ++i) {
        const string& fileName = lstFileName[i];

        // Read file
        cout << "[ ReadFile ] Start " << fileName << endl;
        sleepsec(10);
        cout << "[ ReadFile ] Done  " << fileName << endl;

        {
            boost::unique_lock<boost::mutex>(counter.mut);
            --counter.value;
            counter.cond.notify_one();
        }

        // Write log into disk
        sleepsec(5);
        cout << "[ WriteLog ]" << endl;
    }
}



void processRequest() {
    vector<string> lstFileName;
    lstFileName.push_back("foo.html");
    lstFileName.push_back("bar.json");

    Counter counter(lstFileName.size());

    // The server checks auth user while reading files, concurrently
    boost::thread th(&processFiles, boost::cref(lstFileName), boost::ref(counter));
    checkAuthUser();

    // The server waits for completion of loading files
    {
        boost::unique_lock<boost::mutex> lk(counter.mut);
        while (counter.value > 0) {
            counter.cond.wait_for(lk, boost::chrono::seconds(10)); // timeout = 10 seconds
        }
    }

    cout << "\nNow user is authorized and files are loaded" << endl;
    cout << "Do other tasks...\n" << endl;

    th.join();
}



int main() {
    processRequest();
    return 0;
}


================================================
FILE: cpp/cpp-boost/exer07b-data-server.cpp
================================================
/*
THE DATA SERVER PROBLEM
Version B: Solving the problem using a semaphore
*/


#include <iostream>
#include <string>
#include <vector>
#include <boost/ref.hpp>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include "mylib-semaphore.hpp"
using namespace std;



#define sleepsec(secs) \
    do { boost::this_thread::sleep_for(boost::chrono::seconds(secs)); } while (0)



void checkAuthUser() {
    cout << "[   Auth   ] Start" << endl;
    // Send request to authenticator, check permissions, encrypt, decrypt...
    sleepsec(20);
    cout << "[   Auth   ] Done" << endl;
}



void processFiles(const vector<string>& lstFileName, mylib::Semaphore& sem) {
    for (size_t i = 0; i < lstFileName.size(); ++i) {
        const string& fileName = lstFileName[i];

        // Read file
        cout << "[ ReadFile ] Start " << fileName << endl;
        sleepsec(10);
        cout << "[ ReadFile ] Done  " << fileName << endl;

        sem.release();

        // Write log into disk
        sleepsec(5);
        cout << "[ WriteLog ]" << endl;
    }
}



void processRequest() {
    vector<string> lstFileName;
    lstFileName.push_back("foo.html");
    lstFileName.push_back("bar.json");

    mylib::Semaphore sem(0);

    // The server checks auth user while reading files, concurrently
    boost::thread th(&processFiles, boost::cref(lstFileName), boost::ref(sem));
    checkAuthUser();

    // The server waits for completion of loading files
    for (size_t i = lstFileName.size(); i > 0; --i) {
        sem.acquire();
    }

    cout << "\nNow user is authorized and files are loaded" << endl;
    cout << "Do other tasks...\n" << endl;

    th.join();
}



int main() {
    processRequest();
    return 0;
}


================================================
FILE: cpp/cpp-boost/exer07c-data-server.cpp
================================================
/*
THE DATA SERVER PROBLEM
Version C: Solving the problem using a count-down latch
*/


#include <iostream>
#include <string>
#include <vector>
#include <boost/ref.hpp>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include <boost/thread/latch.hpp>
using namespace std;



#define sleepsec(secs) \
    do { boost::this_thread::sleep_for(boost::chrono::seconds(secs)); } while (0)



void checkAuthUser() {
    cout << "[   Auth   ] Start" << endl;
    // Send request to authenticator, check permissions, encrypt, decrypt...
    sleepsec(20);
    cout << "[   Auth   ] Done" << endl;
}



void processFiles(const vector<string>& lstFileName, boost::latch& rdLatch) {
    for (size_t i = 0; i < lstFileName.size(); ++i) {
        const string& fileName = lstFileName[i];

        // Read file
        cout << "[ ReadFile ] Start " << fileName << endl;
        sleepsec(10);
        cout << "[ ReadFile ] Done  " << fileName << endl;

        rdLatch.count_down();

        // Write log into disk
        sleepsec(5);
        cout << "[ WriteLog ]" << endl;
    }
}



void processRequest() {
    vector<string> lstFileName;
    lstFileName.push_back("foo.html");
    lstFileName.push_back("bar.json");

    boost::latch readFileLatch(lstFileName.size());

    // The server checks auth user while reading files, concurrently
    boost::thread th(&processFiles, boost::cref(lstFileName), boost::ref(readFileLatch));
    checkAuthUser();

    // The server waits for completion of loading files
    readFileLatch.wait();

    cout << "\nNow user is authorized and files are loaded" << endl;
    cout << "Do other tasks...\n" << endl;

    th.join();
}



int main() {
    processRequest();
    return 0;
}


================================================
FILE: cpp/cpp-boost/exer07d-data-server.cpp
================================================
/*
THE DATA SERVER PROBLEM
Version D: Solving the problem using a blocking queue
*/


#include <iostream>
#include <string>
#include <vector>
#include <boost/ref.hpp>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include "mylib-blockingqueue.hpp"
using namespace std;



#define sleepsec(secs) \
    do { boost::this_thread::sleep_for(boost::chrono::seconds(secs)); } while (0)



void checkAuthUser() {
    cout << "[   Auth   ] Start" << endl;
    // Send request to authenticator, check permissions, encrypt, decrypt...
    sleepsec(20);
    cout << "[   Auth   ] Done" << endl;
}



void processFiles(const vector<string>& lstFileName, mylib::BlockingQueue<string>& blkq) {
    for (size_t i = 0; i < lstFileName.size(); ++i) {
        const string& fileName = lstFileName[i];

        // Read file
        cout << "[ ReadFile ] Start " << fileName << endl;
        sleepsec(10);
        cout << "[ ReadFile ] Done  " << fileName << endl;

        blkq.put(fileName); // You may put file data here

        // Write log into disk
        sleepsec(5);
        cout << "[ WriteLog ]" << endl;
    }
}



void processRequest() {
    vector<string> lstFileName;
    lstFileName.push_back("foo.html");
    lstFileName.push_back("bar.json");

    mylib::BlockingQueue<string> blkq;

    // The server checks auth user while reading files, concurrently
    boost::thread th(&processFiles, boost::cref(lstFileName), boost::ref(blkq));
    checkAuthUser();

    // The server waits for completion of loading files
    for (size_t i = lstFileName.size(); i > 0; --i) {
        blkq.take();
    }

    cout << "\nNow user is authorized and files are loaded" << endl;
    cout << "Do other tasks...\n" << endl;

    th.join();
}



int main() {
    processRequest();
    return 0;
}


================================================
FILE: cpp/cpp-boost/exer08-exec-service-itask.hpp
================================================
#ifndef _MY_EXEC_SERVICE_ITASK_HPP_
#define _MY_EXEC_SERVICE_ITASK_HPP_



// interface ITask
class ITask {
public:
    virtual ~ITask() { }
    virtual void run() = 0;
};



#endif // _MY_EXEC_SERVICE_ITASK_HPP_


================================================
FILE: cpp/cpp-boost/exer08-exec-service-main.cpp
================================================
/*
EXECUTOR SERVICE & THREAD POOL IMPLEMENTATION
*/


#include <iostream>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include "exer08-exec-service-itask.hpp"
#include "exer08-exec-service-v0a.hpp"
#include "exer08-exec-service-v0b.hpp"
#include "exer08-exec-service-v1a.hpp"
#include "exer08-exec-service-v1b.hpp"
#include "exer08-exec-service-v2a.hpp"
#include "exer08-exec-service-v2b.hpp"



class MyTask : public ITask {
public:
    char id;

public:
    void run() {
        std::cout << "Task " << id << " is starting" << std::endl;
        boost::this_thread::sleep_for(boost::chrono::seconds(3));
        std::cout << "Task " << id << " is completed" << std::endl;
    }
};



int main() {
    const int NUM_THREADS = 2;
    const int NUM_TASKS = 5;


    MyExecServiceV0A execService(NUM_THREADS);


    std::vector<MyTask> lstTask(NUM_TASKS);

    for (int i = 0; i < NUM_TASKS; ++i)
        lstTask[i].id = 'A' + i;


    for (int i = 0; i < NUM_TASKS; ++i) {
        execService.submit(&lstTask[i]);
    }

    std::cout << "All tasks are submitted" << std::endl;


    execService.waitTaskDone();
    std::cout << "All tasks are completed" << std::endl;


    execService.shutdown();


    return 0;
}


================================================
FILE: cpp/cpp-boost/exer08-exec-service-v0a.hpp
================================================
/*
MY EXECUTOR SERVICE

Version 0A: The easiest executor service
- It uses a blocking queue as underlying mechanism.
*/



#ifndef _MY_EXEC_SERVICE_V0A_HPP_
#define _MY_EXEC_SERVICE_V0A_HPP_



#include <iostream>
#include <vector>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include "mylib-blockingqueue.hpp"
#include "exer08-exec-service-itask.hpp"



class MyExecServiceV0A {

private:
    int numThreads;
    boost::thread_group lstTh;
    mylib::BlockingQueue<ITask*> taskPending;


public:
    MyExecServiceV0A(int numThreads) {
        init(numThreads);
    }


private:
    MyExecServiceV0A(const MyExecServiceV0A& other) : numThreads(0) { }
    void operator=(const MyExecServiceV0A& other) { }

#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900)
    MyExecServiceV0A(const MyExecServiceV0A&& other) : numThreads(0) { }
    void operator=(const MyExecServiceV0A&& other) { }
#endif


private:
    void init(int numThreads) {
        this->numThreads = numThreads;

        for (int i = 0; i < numThreads; ++i) {
            lstTh.add_thread(new boost::thread(&threadWorkerFunc, this));
        }
    }


public:
    void submit(ITask* task) {
        taskPending.add(task);
    }


    void waitTaskDone() {
        // This ExecService is too simple,
        // so there is no implementation for waitTaskDone()
        boost::this_thread::sleep_for(boost::chrono::seconds(11)); // fake behaviour
    }


    void shutdown() {
        // This ExecService is too simple,
        // so there is no implementation for shutdown()
        std::cout << "No implementation for shutdown()." << std::endl;
        std::cout << "You need to exit the app manually." << std::endl;
        lstTh.join_all();
    }


private:
    static void threadWorkerFunc(MyExecServiceV0A* thisPtr) {
        mylib::BlockingQueue<ITask*> & taskPending = thisPtr->taskPending;
        ITask* task = 0;

        for (;;) {
            // WAIT FOR AN AVAILABLE PENDING TASK
            task = taskPending.take();

            // DO THE TASK
            task->run();
        }
    }

};



#endif // _MY_EXEC_SERVICE_V0A_HPP_


================================================
FILE: cpp/cpp-boost/exer08-exec-service-v0b.hpp
================================================
/*
MY EXECUTOR SERVICE

Version 0B: The easiest executor service
- It uses a blocking queue as underlying mechanism.
- It supports waitTaskDone() and shutdown().
*/



#ifndef _MY_EXEC_SERVICE_V0B_HPP_
#define _MY_EXEC_SERVICE_V0B_HPP_



#include <vector>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include "mylib-blockingqueue.hpp"
#include "exer08-exec-service-itask.hpp"



class MyExecServiceV0B {

private:
    int numThreads;
    boost::thread_group lstTh;

    mylib::BlockingQueue<ITask*> taskPending;
    boost::atomic_int32_t counterTaskRunning;

    volatile bool forceThreadShutdown;

    const class : ITask {
        void run() { }
    }
    emptyTask;


public:
    MyExecServiceV0B(int numThreads) {
        init(numThreads);
    }


private:
    MyExecServiceV0B(const MyExecServiceV0B& other) : numThreads(0) { }
    void operator=(const MyExecServiceV0B& other) { }

#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900)
    MyExecServiceV0B(const MyExecServiceV0B&& other) : numThreads(0) { }
    void operator=(const MyExecServiceV0B&& other) { }
#endif


private:
    void init(int numThreads) {
        this->numThreads = numThreads;
        counterTaskRunning = 0;
        forceThreadShutdown = false;

        for (int i = 0; i < numThreads; ++i) {
            lstTh.add_thread(new boost::thread(&threadWorkerFunc, this));
        }
    }


public:
    void submit(ITask* task) {
        taskPending.add(task);
    }


    void waitTaskDone() {
        // This ExecService is too simple,
        // so there is no good implementation for waitTaskDone()
        while (false == taskPending.empty() || counterTaskRunning > 0) {
            boost::this_thread::sleep_for(boost::chrono::seconds(1));
            // boost::this_thread::yield();
        }
    }


    void shutdown() {
        forceThreadShutdown = true;
        taskPending.clear();

        // Invoke blocked threads by adding "empty" tasks
        for (int i = 0; i < numThreads; ++i) {
            taskPending.put( (ITask* const) &emptyTask );
        }

        lstTh.join_all();
        numThreads = 0;
    }


private:
    static void threadWorkerFunc(MyExecServiceV0B* thisPtr) {
        mylib::BlockingQueue<ITask*> & taskPending = thisPtr->taskPending;
        boost::atomic_int32_t & counterTaskRunning = thisPtr->counterTaskRunning;
        volatile bool & forceThreadShutdown = thisPtr->forceThreadShutdown;

        ITask* task = 0;

        for (;;) {
            // WAIT FOR AN AVAILABLE PENDING TASK
            task = taskPending.take();

            // If shutdown() was called, then exit the function
            if (forceThreadShutdown) {
                break;
            }

            // DO THE TASK
            ++counterTaskRunning;
            task->run();
            --counterTaskRunning;
        }
    }

};



#endif // _MY_EXEC_SERVICE_V0B_HPP_


================================================
FILE: cpp/cpp-boost/exer08-exec-service-v1a.hpp
================================================
/*
MY EXECUTOR SERVICE

Version 1A: Simple executor service
- Method "waitTaskDone" invokes thread sleeps in loop (which can cause performance problems).
*/



#ifndef _MY_EXEC_SERVICE_V1A_HPP_
#define _MY_EXEC_SERVICE_V1A_HPP_



#include <vector>
#include <queue>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include "exer08-exec-service-itask.hpp"



class MyExecServiceV1A {

private:
    typedef boost::unique_lock<boost::mutex> uniquelk;


private:
    int numThreads;
    boost::thread_group lstTh;

    std::queue<ITask*> taskPending;
    boost::mutex mutTaskPending;
    boost::condition_variable condTaskPending;

    boost::atomic_int32_t counterTaskRunning;

    volatile bool forceThreadShutdown;


public:
    MyExecServiceV1A(int numThreads) {
        init(numThreads);
    }


private:
    MyExecServiceV1A(const MyExecServiceV1A& other) : numThreads(0) { }
    void operator=(const MyExecServiceV1A& other) { }

#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900)
    MyExecServiceV1A(const MyExecServiceV1A&& other) : numThreads(0) { }
    void operator=(const MyExecServiceV1A&& other) { }
#endif


private:
    void init(int numThreads) {
        // shutdown();

        this->numThreads = numThreads;
        counterTaskRunning = 0;
        forceThreadShutdown = false;

        for (int i = 0; i < numThreads; ++i) {
            lstTh.add_thread(new boost::thread(&threadWorkerFunc, this));
        }
    }


public:
    void submit(ITask* task) {
        {
            uniquelk lk(mutTaskPending);
            taskPending.push(task);
        }

        condTaskPending.notify_one();
    }


    void waitTaskDone() {
        bool done = false;

        for (;;) {
            {
                uniquelk lk(mutTaskPending);

                if (taskPending.empty() && 0 == counterTaskRunning) {
                    done = true;
                }
            }

            if (done) {
                break;
            }

            boost::this_thread::sleep_for(boost::chrono::seconds(1));
            // boost::this_thread::yield();
        }
    }


    void shutdown() {
        {
            uniquelk lk(mutTaskPending);
            forceThreadShutdown = true;

            while (false == taskPending.empty())
                taskPending.pop();
        }

        condTaskPending.notify_all();
        lstTh.join_all();
        numThreads = 0;
    }


private:
    static void threadWorkerFunc(MyExecServiceV1A* thisPtr) {
        std::queue<ITask*> & taskPending = thisPtr->taskPending;
        boost::mutex & mutTaskPending = thisPtr->mutTaskPending;
        boost::condition_variable & condTaskPending = thisPtr->condTaskPending;

        boost::atomic_int32_t & counterTaskRunning = thisPtr->counterTaskRunning;
        volatile bool & forceThreadShutdown = thisPtr->forceThreadShutdown;

        ITask* task = 0;


        for (;;) {
            {
                // WAIT FOR AN AVAILABLE PENDING TASK
                uniquelk lkPending(mutTaskPending);

                while (taskPending.empty() && false == forceThreadShutdown) {
                    condTaskPending.wait(lkPending);
                }

                if (forceThreadShutdown) {
                    // lkPending.unlock(); // remember this statement
                    break;
                }

                // GET THE TASK FROM THE PENDING QUEUE
                task = taskPending.front();
                taskPending.pop();

                ++counterTaskRunning;
            }

            // DO THE TASK
            task->run();

            --counterTaskRunning;
        }
    }

};



#endif // _MY_EXEC_SERVICE_V1A_HPP_


================================================
FILE: cpp/cpp-boost/exer08-exec-service-v1b.hpp
================================================
/*
MY EXECUTOR SERVICE

Version 1B: Simple executor service
- Method "waitTaskDone" uses a condition variable to synchronize.
*/



#ifndef _MY_EXEC_SERVICE_V1B_HPP_
#define _MY_EXEC_SERVICE_V1B_HPP_



#include <vector>
#include <queue>
#include <boost/thread.hpp>
#include "exer08-exec-service-itask.hpp"



class MyExecServiceV1B {

private:
    typedef boost::unique_lock<boost::mutex> uniquelk;


private:
    int numThreads;
    boost::thread_group lstTh;

    std::queue<ITask*> taskPending;
    boost::mutex mutTaskPending;
    boost::condition_variable condTaskPending;

    int counterTaskRunning;
    boost::mutex mutTaskRunning;
    boost::condition_variable condTaskRunning;

    volatile bool forceThreadShutdown;


public:
    MyExecServiceV1B(int numThreads) {
        init(numThreads);
    }


private:
    MyExecServiceV1B(const MyExecServiceV1B& other) : numThreads(0) { }
    void operator=(const MyExecServiceV1B& other) { }

#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900)
    MyExecServiceV1B(const MyExecServiceV1B&& other) : numThreads(0) { }
    void operator=(const MyExecServiceV1B&& other) { }
#endif


private:
    void init(int numThreads) {
        // shutdown();

        this->numThreads = numThreads;
        counterTaskRunning = 0;
        forceThreadShutdown = false;

        for (int i = 0; i < numThreads; ++i) {
            lstTh.add_thread(new boost::thread(&threadWorkerFunc, this));
        }
    }


public:
    void submit(ITask* task) {
        {
            uniquelk lk(mutTaskPending);
            taskPending.push(task);
        }

        condTaskPending.notify_one();
    }


    void waitTaskDone() {
        for (;;) {
            uniquelk lkPending(mutTaskPending);

            if (taskPending.empty()) {
                uniquelk lkRunning(mutTaskRunning);

                while (counterTaskRunning > 0)
                    condTaskRunning.wait(lkRunning);

                // no pending task and no running task
                break;
            }
        }
    }


    void shutdown() {
        {
            uniquelk lk(mutTaskPending);
            forceThreadShutdown = true;

            while (false == taskPending.empty())
                taskPending.pop();
        }

        condTaskPending.notify_all();
        lstTh.join_all();
        numThreads = 0;
    }


private:
    static void threadWorkerFunc(MyExecServiceV1B* thisPtr) {
        std::queue<ITask*> & taskPending = thisPtr->taskPending;
        boost::mutex & mutTaskPending = thisPtr->mutTaskPending;
        boost::condition_variable & condTaskPending = thisPtr->condTaskPending;

        int & counterTaskRunning = thisPtr->counterTaskRunning;
        boost::mutex & mutTaskRunning = thisPtr->mutTaskRunning;
        boost::condition_variable & condTaskRunning = thisPtr->condTaskRunning;

        volatile bool & forceThreadShutdown = thisPtr->forceThreadShutdown;

        ITask* task = 0;


        for (;;) {
            {
                // WAIT FOR AN AVAILABLE PENDING TASK
                uniquelk lkPending(mutTaskPending);

                while (taskPending.empty() && false == forceThreadShutdown) {
                    condTaskPending.wait(lkPending);
                }

                if (forceThreadShutdown) {
                    // lkPending.unlock(); // remember this statement
                    break;
                }

                // GET THE TASK FROM THE PENDING QUEUE
                task = taskPending.front();
                taskPending.pop();

                ++counterTaskRunning;
            }

            // DO THE TASK
            task->run();

            {
                uniquelk lkRunning(mutTaskRunning);
                --counterTaskRunning;

                if (0 == counterTaskRunning) {
                    condTaskRunning.notify_one();
                }
            }
        }
    }

};



#endif // _MY_EXEC_SERVICE_V1B_HPP_


================================================
FILE: cpp/cpp-boost/exer08-exec-service-v2a.hpp
================================================
/*
MY EXECUTOR SERVICE

Version 2A: The executor service storing running tasks
- Method "waitTaskDone" uses a semaphore to synchronize.
*/



#ifndef _MY_EXEC_SERVICE_V2A_HPP_
#define _MY_EXEC_SERVICE_V2A_HPP_



#include <vector>
#include <list>
#include <queue>
#include <boost/thread.hpp>
#include "mylib-semaphore.hpp"
#include "exer08-exec-service-itask.hpp"



class MyExecServiceV2A {

private:
    typedef boost::unique_lock<boost::mutex> uniquelk;


private:
    int numThreads;
    boost::thread_group lstTh;

    std::queue<ITask*> taskPending;
    boost::mutex mutTaskPending;
    boost::condition_variable condTaskPending;

    std::list<ITask*> taskRunning;
    boost::mutex mutTaskRunning;
    mylib::Semaphore counterTaskRunning;

    volatile bool forceThreadShutdown;


public:
    MyExecServiceV2A(int numThreads) : counterTaskRunning(0) {
        init(numThreads);
    }


private:
    MyExecServiceV2A(const MyExecServiceV2A& other) : numThreads(0), counterTaskRunning(0) { }
    void operator=(const MyExecServiceV2A& other) { }

#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900)
    MyExecServiceV2A(const MyExecServiceV2A&& other) : numThreads(0), counterTaskRunning(0) { }
    void operator=(const MyExecServiceV2A&& other) { }
#endif


private:
    void init(int numThreads) {
        // shutdown();

        this->numThreads = numThreads;
        forceThreadShutdown = false;

        for (int i = 0; i < numThreads; ++i) {
            lstTh.add_thread(new boost::thread(&threadWorkerFunc, this));
        }
    }


public:
    void submit(ITask* task) {
        {
            uniquelk lk(mutTaskPending);
            taskPending.push(task);
        }

        condTaskPending.notify_one();
    }


    void waitTaskDone() {
        for (;;) {
            counterTaskRunning.acquire();

            {
                uniquelk lkPending(mutTaskPending);
                uniquelk lkRunning(mutTaskRunning);

                if (taskPending.empty() && taskRunning.empty()) {
                    break;
                }
            }
        }
    }


    void shutdown() {
        {
            uniquelk lk(mutTaskPending);
            forceThreadShutdown = true;

            while (false == taskPending.empty())
                taskPending.pop();
        }

        condTaskPending.notify_all();
        lstTh.join_all();
        numThreads = 0;
    }


private:
    static void threadWorkerFunc(MyExecServiceV2A* thisPtr) {
        std::queue<ITask*> & taskPending = thisPtr->taskPending;
        boost::mutex & mutTaskPending = thisPtr->mutTaskPending;
        boost::condition_variable & condTaskPending = thisPtr->condTaskPending;

        std::list<ITask*> & taskRunning = thisPtr->taskRunning;
        boost::mutex & mutTaskRunning = thisPtr->mutTaskRunning;
        mylib::Semaphore & counterTaskRunning = thisPtr->counterTaskRunning;

        volatile bool & forceThreadShutdown = thisPtr->forceThreadShutdown;

        ITask* task = 0;


        for (;;) {
            {
                // WAIT FOR AN AVAILABLE PENDING TASK
                uniquelk lkPending(mutTaskPending);

                while (taskPending.empty() && false == forceThreadShutdown) {
                    condTaskPending.wait(lkPending);
                }

                if (forceThreadShutdown) {
                    // lkPending.unlock(); // remember this statement
                    break;
                }

                // GET THE TASK FROM THE PENDING QUEUE
                task = taskPending.front();
                taskPending.pop();

                // PUSH IT TO THE RUNNING QUEUE
                {
                    uniquelk lkRunning(mutTaskRunning);
                    taskRunning.push_back(task);
                }
            }

            // DO THE TASK
            task->run();

            // REMOVE IT FROM THE RUNNING QUEUE
            {
                uniquelk lkRunning(mutTaskRunning);
                taskRunning.remove(task);
                counterTaskRunning.release();
            }
        }
    }

};



#endif // _MY_EXEC_SERVICE_V2A_HPP_


================================================
FILE: cpp/cpp-boost/exer08-exec-service-v2b.hpp
================================================
/*
MY EXECUTOR SERVICE

Version 2B: The executor service storing running tasks
- Method "waitTaskDone" uses a condition variable to synchronize.
*/



#ifndef _MY_EXEC_SERVICE_V2B_HPP_
#define _MY_EXEC_SERVICE_V2B_HPP_



#include <vector>
#include <list>
#include <queue>
#include <boost/thread.hpp>
#include "exer08-exec-service-itask.hpp"



class MyExecServiceV2B {

private:
    typedef boost::unique_lock<boost::mutex> uniquelk;


private:
    int numThreads;
    boost::thread_group lstTh;

    std::queue<ITask*> taskPending;
    boost::mutex mutTaskPending;
    boost::condition_variable condTaskPending;

    std::list<ITask*> taskRunning;
    boost::mutex mutTaskRunning;
    boost::condition_variable condTaskRunning;

    volatile bool forceThreadShutdown;


public:
    MyExecServiceV2B(int numThreads) {
        init(numThreads);
    }


private:
    MyExecServiceV2B(const MyExecServiceV2B& other) : numThreads(0) { }
    void operator=(const MyExecServiceV2B& other) { }

#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900)
    MyExecServiceV2B(const MyExecServiceV2B&& other) : numThreads(0) { }
    void operator=(const MyExecServiceV2B&& other) { }
#endif


private:
    void init(int numThreads) {
        // shutdown();

        this->numThreads = numThreads;
        forceThreadShutdown = false;

        for (int i = 0; i < numThreads; ++i) {
            lstTh.add_thread(new boost::thread(&threadWorkerFunc, this));
        }
    }


public:
    void submit(ITask* task) {
        {
            uniquelk lk(mutTaskPending);
            taskPending.push(task);
        }

        condTaskPending.notify_one();
    }


    void waitTaskDone() {
        for (;;) {
            uniquelk lkPending(mutTaskPending);

            if (taskPending.empty()) {
                uniquelk lkRunning(mutTaskRunning);

                while (false == taskRunning.empty())
                    condTaskRunning.wait(lkRunning);

                // no pending task and no running task
                break;
            }
        }
    }


    void shutdown() {
        {
            uniquelk lk(mutTaskPending);
            forceThreadShutdown = true;

            while (false == taskPending.empty())
                taskPending.pop();
        }

        condTaskPending.notify_all();
        lstTh.join_all();
        numThreads = 0;
    }


private:
    static void threadWorkerFunc(MyExecServiceV2B* thisPtr) {
        std::queue<ITask*> & taskPending = thisPtr->taskPending;
        boost::mutex & mutTaskPending = thisPtr->mutTaskPending;
        boost::condition_variable & condTaskPending = thisPtr->condTaskPending;

        std::list<ITask*> & taskRunning = thisPtr->taskRunning;
        boost::mutex & mutTaskRunning = thisPtr->mutTaskRunning;
        boost::condition_variable & condTaskRunning = thisPtr->condTaskRunning;

        volatile bool & forceThreadShutdown = thisPtr->forceThreadShutdown;

        ITask* task = 0;


        for (;;) {
            {
                // WAIT FOR AN AVAILABLE PENDING TASK
                uniquelk lkPending(mutTaskPending);

                while (taskPending.empty() && false == forceThreadShutdown) {
                    condTaskPending.wait(lkPending);
                }

                if (forceThreadShutdown) {
                    // lkPending.unlock(); // remember this statement
                    break;
                }

                // GET THE TASK FROM THE PENDING QUEUE
                task = taskPending.front();
                taskPending.pop();

                // PUSH IT TO THE RUNNING QUEUE
                {
                    uniquelk lkRunning(mutTaskRunning);
                    taskRunning.push_back(task);
                }
            }

            // DO THE TASK
            task->run();

            // REMOVE IT FROM THE RUNNING QUEUE
            {
                uniquelk lkRunning(mutTaskRunning);
                taskRunning.remove(task);
                condTaskRunning.notify_one();
            }
        }
    }

};



#endif // _MY_EXEC_SERVICE_V2B_HPP_


================================================
FILE: cpp/cpp-boost/mylib-blockingqueue.hpp
================================================
/******************************************************
*
* File name:    mylib-blockingqueue.hpp
*
* Author:       Name:   Thanh Nguyen
*               Email:  thanh.it1995(at)gmail(dot)com
*
* License:      3-Clause BSD License
*
* Description:  The blocking queue implementation in C++98 Boost threading
*
******************************************************/



#ifndef _MYLIB_BLOCKING_QUEUE_HPP_
#define _MYLIB_BLOCKING_QUEUE_HPP_



#include <limits>
#include <queue>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/lock_types.hpp>
#include <boost/thread/thread.hpp>



namespace mylib
{



template <typename T>
class BlockingQueue {

private:
    typedef boost::unique_lock<boost::mutex> uniquelk;


private:
    boost::condition_variable condEmpty;
    boost::condition_variable condFull;
    boost::mutex mut;

    size_t capacity;
    std::queue<T> q;


public:
    BlockingQueue() : capacity(std::numeric_limits<size_t>::max()) {
    }


    BlockingQueue(size_t capacity) : capacity(capacity) {
    }


private:
    BlockingQueue(const BlockingQueue& other) { }
    void operator=(const BlockingQueue& other) { }

#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900)
    BlockingQueue(const BlockingQueue&& other) { }
    void operator=(const BlockingQueue&& other) { }
#endif


public:
    bool empty() const {
        return q.empty();
    }


    size_t size() const {
        return q.size();
    }


    // sync enqueue
    void put(const T& value) {
        uniquelk lk(mut);

        while (q.size() >= capacity) {
            condFull.wait(lk);
        }

        q.push(value);
        condEmpty.notify_one();
    }


    // sync dequeue
    T take() {
        uniquelk lk(mut);

        while (q.empty()) {
            condEmpty.wait(lk);
        }

        T result = q.front();
        q.pop();
        condFull.notify_one();

        return result;
    }


    // async enqueue
    void add(const T& value) {
        // Note: For asynchronous operations, we should use a long-live background thread
        // instead of using a temporary thread
        boost::thread(&BlockingQueue<T>::put, this, value).detach();
    }


    // returns false if queue is empty, otherwise returns true and assigns the result
    bool peek(T& result) const {
        uniquelk(mut);

        if (q.empty()) {
            return false;
        }

        result = q.front();
        return true;
    }


    void clear() {
        uniquelk(mut);

        while (false == q.empty()) {
            q.pop();
        }
    }

}; // BlockingQueue



} // namespace mylib



#endif // _MYLIB_BLOCKING_QUEUE_HPP_


================================================
FILE: cpp/cpp-boost/mylib-random.hpp
================================================
/******************************************************
*
* File name:    mylib-random.hpp
*
* Author:       Name:   Thanh Nguyen
*               Email:  thanh.it1995(at)gmail(dot)com
*
* License:      3-Clause BSD License
*
* Description:  The random utility in C++98 Boost
*
******************************************************/



#ifndef _MYLIB_RANDOM_HPP_
#define _MYLIB_RANDOM_HPP_



#include <limits>
#include <boost/random/random_device.hpp>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int_distribution.hpp>



namespace mylib {



class RandInt {

private:
    boost::random::random_device rd;
    boost::random::mt19937 mt;
    boost::random::uniform_int_distribution<int> dist;


public:
    RandInt() {
        init(0, std::numeric_limits<int>::max());
    }


    RandInt(int minValue, int maxValueInclusive) {
        init(minValue, maxValueInclusive);
    }


    void init(int minValue, int maxValueInclusive) {
        dist = boost::random::uniform_int_distribution<int>(minValue, maxValueInclusive);
        mt.seed(rd());
    }


    int next() {
        return dist(mt);
    }


private:
    RandInt(const RandInt& other) { }
    void operator=(const RandInt& other) { }


// STATIC
private:
    static RandInt publicRandInt;

public:
    static int get(int maxExclusive) {
        return publicRandInt.next() % maxExclusive;
    }

}; // RandInt



RandInt RandInt::publicRandInt;



} // namespace mylib



#endif // _MYLIB_RANDOM_HPP_


================================================
FILE: cpp/cpp-boost/mylib-semaphore.hpp
================================================
/******************************************************
*
* File name:    mylib-semaphore.hpp
*
* Author:       Name:   Thanh Nguyen
*               Email:  thanh.it1995(at)gmail(dot)com
*
* License:      3-Clause BSD License
*
* Description:  The semaphore implementation in C++98 Boost threading
*               This is just a simulation based on the condition variable
*
******************************************************/



#ifndef _MYLIB_SEMAPHORE_HPP_
#define _MYLIB_SEMAPHORE_HPP_



#include <queue>
#include <limits>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/lock_types.hpp>



namespace mylib
{



class Semaphore {

private:
    typedef boost::unique_lock<boost::mutex> uniquelk;


private:
    volatile int value;
    boost::condition_variable condFreeState;
    boost::mutex mut;

    static int MIN_VALUE;
    static int MAX_VALUE;


public:
    Semaphore(int initialValue) {
        this->value = initialValue;
    }


private:
    Semaphore(const Semaphore& other) { }
    void operator=(const Semaphore& other) { }

#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900)
    Semaphore(const Semaphore&& other) { }
    void operator=(const Semaphore&& other) { }
#endif


public:
    void acquire() {
        uniquelk lk(mut);

        while (value <= 0) {
            condFreeState.wait(lk);
        }

        if (value > MIN_VALUE) {
            --value;
        }
    }


    void release() {
        uniquelk lk(mut);

        if (value < MAX_VALUE) {
            ++value;
        }

        if (value >= 0) {
            condFreeState.notify_one();
        }
    }


    int getValue() const {
        return value; // does not block
    }

}; // Semaphore



int Semaphore::MIN_VALUE = std::numeric_limits<int>::min();
int Semaphore::MAX_VALUE = std::numeric_limits<int>::max();



} // namespace mylib



#endif // _MYLIB_SEMAPHORE_HPP_


================================================
FILE: cpp/cpp-boost/mylib-time.hpp
================================================
/******************************************************
*
* File name:    mylib-time.hpp
*
* Author:       Name:   Thanh Nguyen
*               Email:  thanh.it1995(at)gmail(dot)com
*
* License:      3-Clause BSD License
*
* Description:  The time utility in C++98 Boost
*
******************************************************/



#ifndef _MYLIB_TIME_HPP_
#define _MYLIB_TIME_HPP_



#include <ctime>
#include <boost/chrono.hpp>



namespace mylib
{



namespace chro = boost::chrono;
typedef chro::system_clock sysclock;



class HiResClock {

private:
    typedef chro::high_resolution_clock stdhrc;


public:
    static inline stdhrc::time_point now()
    {
        return stdhrc::now();
    }


    template< typename duType >
    static inline
    duType
    getTimeSpan(
        const stdhrc::time_point& tp1,
        const stdhrc::time_point& tp2)
    {
        duType res = chro::duration_cast<duType>(tp2 - tp1);
        return res;
    }


    template< typename duType >
    static inline
    duType
    getTimeSpan(const stdhrc::time_point& tpBefore)
    {
        stdhrc::time_point tpCurrent = HiResClock::now();
        duType res = HiResClock::getTimeSpan<duType>(tpBefore, tpCurrent);
        return res;
    }

}; // HiResClock



char* getTimePointStr(const sysclock::time_point& tp) {
    std::time_t timeStamp = sysclock::to_time_t(tp);
    return std::ctime(&timeStamp);
}



template<class clock>
class clock::time_point getTimePoint(
    int year, int month, int day,
    int hour, int minute, int second)
{
    std::tm t;
    t.tm_year = year - 1900;
    t.tm_mon = month - 1;
    t.tm_mday = day;
    t.tm_hour = hour;
    t.tm_min = minute;
    t.tm_sec = second;
    return clock::from_time_t(std::mktime(&t));
}



// tp += numSeconds * 2;
// tp -= (x % numSeconds)
template<class clock, typename duType>
chro::time_point<clock>
getTimePointFutureFloor(const chro::time_point<clock>& tp, int numSeconds) {
    chro::seconds duSeconds(numSeconds);

    chro::duration<duType> durationFromTp = chro::time_point_cast<chro::seconds>(tp).time_since_epoch();

    chro::duration<duType> durationFuture = durationFromTp + (duSeconds * 2);
    durationFuture = durationFuture - (durationFuture % duSeconds);

    chro::time_point<clock> tpFuture(durationFuture);
    return tpFuture;
}



} // namespace mylib



#endif // _MYLIB_TIME_HPP_


================================================
FILE: cpp/cpp-pthread/demo00.cpp
================================================
/*
INTRODUCTION TO MULTITHREADING
You should try running this app several times and see results.
*/


#include <iostream>
#include <pthread.h>
using namespace std;



void* doTask(void*) {
    for (int i = 0; i < 300; ++i)
        cout << "B";

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    pthread_t tid;
    int ret = 0;

    ret = pthread_create(&tid, nullptr, &doTask, nullptr);

    for (int i = 0; i < 300; ++i)
        cout << "A";

    ret = pthread_join(tid, nullptr);

    cout << endl;
    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo01-hello.cpp
================================================
/*
HELLO WORLD VERSION MULTITHREADING
*/


#include <iostream>
#include <pthread.h>
using namespace std;



void* doTask(void*) {
    cout << "Hello from example thread" << endl;

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    pthread_t tid;
    int ret = 0;

    ret = pthread_create(&tid, nullptr, &doTask, nullptr);

    /*
    if (ret) {
        cerr << "Error: Unable to create thread " << ret << endl;
        return 1;
    }
    */

    ret = pthread_join(tid, nullptr);
    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo02-join.cpp
================================================
/*
THREAD JOINS
*/


#include <iostream>
#include <pthread.h>
using namespace std;



void* doHeavyTask(void*) {
    // Do a heavy task, which takes a little time
    for (int i = 0; i < 2000000000; ++i);

    cout << "Done!" << endl;

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    pthread_t tid;
    int ret = 0;

    ret = pthread_create(&tid, nullptr, &doHeavyTask, nullptr);

    ret = pthread_join(tid, nullptr);

    cout << "Good bye!" << endl;

    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo03a01-pass-arg.cpp
================================================
/*
PASSING ARGUMENTS
Version A01: The problem

The id in statement "hello pthread with id..." might be DUPLICATED!!!
Reason: Passing the address of variable i,
        so that all threads use a same value of i.
*/


#include <iostream>
#include <pthread.h>
using namespace std;



void* doTask(void* ptrId) {
    int id = *(int*)ptrId;

    cout << "Hello pthread with id = " << id << endl;

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    pthread_t lstTid[2];
    int ret = 0;

    for (int i = 0; i < 2; ++i)
        ret = pthread_create(&lstTid[i], nullptr, &doTask, &i);

    for (int i = 0; i < 2; ++i)
        ret = pthread_join(lstTid[i], nullptr);

    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo03a02-pass-arg.cpp
================================================
/*
PASSING ARGUMENTS
Version A02: Solving the problem
*/


#include <iostream>
#include <pthread.h>
using namespace std;



void* doTask(void* ptrId) {
    int id = *(int*)ptrId;

    cout << "Hello pthread with id = " << id << endl;

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    pthread_t lstTid[2];
    int lstArg[2];
    int ret = 0;

    for (int i = 0; i < 2; ++i) {
        lstArg[i] = i + 1;
        ret = pthread_create(&lstTid[i], nullptr, &doTask, &lstArg[i]);
    }

    for (int i = 0; i < 2; ++i)
        ret = pthread_join(lstTid[i], nullptr);

    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo03b01-pass-arg.cpp
================================================
/*
PASSING MULTIPLE ARGUMENTS
Solution 01: Creating a custom struct
*/


#include <iostream>
#include <string>
#include <pthread.h>
using namespace std;



struct ThreadArg {
    int x;
    double y;
    string z;
};



void* doTask(void* argVoid) {
    auto arg = (ThreadArg*) argVoid;

    cout << arg->x << endl;
    cout << arg->y << endl;
    cout << arg->z << endl;

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    pthread_t tid;
    ThreadArg arg;
    int ret = 0;

    arg.x = 10;
    arg.y = -2.4;
    arg.z = "lorem ipsum";

    ret = pthread_create(&tid, nullptr, &doTask, &arg);
    ret = pthread_join(tid, nullptr);

    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo03b02-pass-arg.cpp
================================================
/*
PASSING MULTIPLE ARGUMENTS
Solution 02: Using std::tuple
*/


#include <iostream>
#include <string>
#include <tuple>
#include <pthread.h>
using namespace std;



void* doTask(void* argVoid) {
    auto arg = * (tuple<int,double,string> *) argVoid;

    cout << std::get<0>(arg) << endl;
    cout << std::get<1>(arg) << endl;
    cout << std::get<2>(arg) << endl;

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    pthread_t tid;
    tuple<int,double,string> arg;
    int ret = 0;

    // arg = std::make_tuple( 10, -2.4, "lorem ipsum" );
    arg = { 10, -2.4, "lorem ipsum" };

    ret = pthread_create(&tid, nullptr, &doTask, &arg);
    ret = pthread_join(tid, nullptr);

    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo04-sleep.cpp
================================================
/*
SLEEP
*/


#include <iostream>
#include <unistd.h>
#include <pthread.h>
using namespace std;



void* doTask(void* arg) {
    auto name = (const char*) arg;

    cout << name << " is sleeping" << endl;
    sleep(2);
    cout << name << " wakes up" << endl;

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    pthread_t tid;
    int ret = 0;

    ret = pthread_create(&tid, nullptr, &doTask, (void*)"foo");

    ret = pthread_join(tid, nullptr);

    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo05-id.cpp
================================================
/*
GETTING THREAD'S ID
*/


#include <iostream>
#include <unistd.h>
#include <pthread.h>
using namespace std;



void* doTask(void*) {
    sleep(2);
    cout << pthread_self() << endl;

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    pthread_t tidFoo, tidBar;
    int ret = 0;

    ret = pthread_create(&tidFoo, nullptr, &doTask, nullptr);
    ret = pthread_create(&tidBar, nullptr, &doTask, nullptr);

    cout << "foo's id = " << tidFoo << endl;
    cout << "bar's id = " << tidBar << endl;

    ret = pthread_join(tidFoo, nullptr);
    ret = pthread_join(tidBar, nullptr);

    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo06a-list-threads.cpp
================================================
/*
LIST OF MULTIPLE THREADS
Version A: Using standard arrays
*/


#include <iostream>
#include <pthread.h>
using namespace std;



void* doTask(void* arg) {
    auto index = *(int*) arg;
    cout << index;

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    constexpr int NUM_THREADS = 5;

    pthread_t lstTid[NUM_THREADS];
    int lstArg[NUM_THREADS];

    int ret = 0;


    for (int i = 0; i < NUM_THREADS; ++i) {
        lstArg[i] = i;
        ret = pthread_create(&lstTid[i], nullptr, &doTask, &lstArg[i]);
    }

    for (auto&& tid : lstTid) {
        ret = pthread_join(tid, nullptr);
    }


    cout << endl;
    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo06b-list-threads.cpp
================================================
/*
LIST OF MULTIPLE THREADS
Version B: Using the std::vector
*/


#include <iostream>
#include <vector>
#include <pthread.h>
using namespace std;



void* doTask(void* arg) {
    auto index = *(int*) arg;
    cout << index;

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    constexpr int NUM_THREADS = 5;

    vector<pthread_t> lstTid(NUM_THREADS);
    vector<int> lstArg(NUM_THREADS);

    int ret = 0;


    for (int i = 0; i < NUM_THREADS; ++i) {
        lstArg[i] = i;
        ret = pthread_create(&lstTid[i], nullptr, &doTask, &lstArg[i]);
    }

    for (auto&& tid : lstTid) {
        ret = pthread_join(tid, nullptr);
    }


    cout << endl;
    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo07a-terminate.cpp
================================================
/*
FORCING A THREAD TO TERMINATE (i.e. killing the thread)
Version A: Using the flag 'isRunning'
*/


#include <iostream>
#include <unistd.h>
#include <pthread.h>
using namespace std;



volatile bool isRunning;



void* doTask(void*) {
    while (isRunning) {
        cout << "Running..." << endl;
        sleep(2);
    }

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    pthread_t tid;
    int ret = 0;

    isRunning = true;
    ret = pthread_create(&tid, nullptr, &doTask, nullptr);

    sleep(6);
    isRunning = false;

    ret = pthread_join(tid, nullptr);
    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo07b-terminate.cpp
================================================
/*
FORCING A THREAD TO TERMINATE (i.e. killing the thread)
Version B: Using pthread_cancel
*/


#include <iostream>
#include <unistd.h>
#include <pthread.h>
using namespace std;



void* doTask(void*) {
    while (1) {
        cout << "Running..." << endl;
        sleep(1);
    }

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    pthread_t tid;
    int ret = 0;

    ret = pthread_create(&tid, nullptr, &doTask, nullptr);

    sleep(3);

    ret = pthread_cancel(tid);

    ret = pthread_join(tid, nullptr);

    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo08a-return-value.cpp
================================================
/*
GETTING RETURNED VALUES FROM THREADS
Version A: Values returned via pointers passed from arguments
*/


#include <iostream>
#include <pthread.h>
using namespace std;



struct ThreadArg {
    int value;
    int *res;
};



void* doubleValue(void* argVoid) {
    auto arg = (ThreadArg*) argVoid;

    *(arg->res) = arg->value * 2;

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    pthread_t tid;
    int result;
    ThreadArg arg;
    int ret = 0;

    arg = { 80, &result };

    ret = pthread_create(&tid, nullptr, &doubleValue, &arg);
    ret = pthread_join(tid, nullptr);

    cout << result << endl;
    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo08b-return-value.cpp
================================================
/*
GETTING RETURNED VALUES FROM THREADS
Version B: Values returned via pthread_exit
*/


#include <iostream>
#include <pthread.h>
using namespace std;



void* doubleValue(void* arg) {
    auto value = *(int*) arg;

    int *result = new int;
    *result = value * 2;

    pthread_exit((void*)result);
    return (void*)result;
}



int main() {
    pthread_t tid;
    int arg = 80;
    int *result = nullptr;
    int ret = 0;

    ret = pthread_create(&tid, nullptr, &doubleValue, &arg);
    ret = pthread_join(tid, (void**)&result);

    cout << (*result) << endl;

    delete result;
    result = nullptr;

    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo09a-detach.cpp
================================================
/*
THREAD DETACHING
*/


#include <iostream>
#include <unistd.h>
#include <pthread.h>
using namespace std;



void* foo(void*) {
    cout << "foo is starting..." << endl;

    sleep(2);

    cout << "foo is exiting..." << endl;

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    pthread_t tidFoo;
    int ret = 0;


    ret = pthread_create(&tidFoo, nullptr, &foo, nullptr);
    ret = pthread_detach(tidFoo);

    if (ret) {
        cout << "Error: Cannot detach tidFoo" << endl;
    }


    // ret = pthread_join(tidFoo, nullptr);
    // if (ret) {
    //     cout << "Error: Cannot join tidFoo" << endl;
    // }


    // If I comment this statement,
    // tidFoo will be forced into terminating with main thread
    sleep(3);


    cout << "Main thread is exiting" << endl;
    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo09b-detach.cpp
================================================
/*
THREAD DETACHING
*/


#include <iostream>
#include <unistd.h>
#include <pthread.h>
using namespace std;



void* foo(void*) {
    int ret = 0;

    cout << "foo is starting..." << endl;

    if ( ret = pthread_detach(pthread_self()) ) {
        cout << "Error: Cannot detach" << endl;
    }

    sleep(2);

    cout << "foo is exiting..." << endl;

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    pthread_t tidFoo;
    int ret = 0;

    ret = pthread_create(&tidFoo, nullptr, &foo, nullptr);

    sleep(3);

    cout << "Main thread is exiting" << endl;
    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo10-yield.cpp
================================================
/*
THREAD YIELDING
*/


#include <iostream>
#include <sched.h>
#include <pthread.h>
#include <chrono>
#include "../cpp-std/mylib-time.hpp"
using namespace std;



using chrmicro = std::chrono::microseconds;
using hrclock = mylib::HiResClock;



void littleSleep(int us) {
    auto tpStart = hrclock::now();
    auto tpEnd = tpStart + chrmicro(us);

    int ret = 0;

    do {
        // ret = pthread_yield();
        ret = sched_yield();
    }
    while (hrclock::now() < tpEnd);
}



int main() {
    auto tpStartMeasure = hrclock::now();

    littleSleep(130);

    auto timeElapsed = hrclock::getTimeSpan<chrmicro>(tpStartMeasure);

    cout << "Elapsed time: " << timeElapsed.count() << " microseonds" << endl;
    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo11a-exec-service.cpp
================================================
/*
EXECUTOR SERVICES AND THREAD POOLS

Executor services in C++ POSIX threading are not supported by default.
So, I use mylib::ExecService for this demonstration.
*/


#include <iostream>
#include "mylib-execservice.hpp"
using namespace std;



void doTask() {
    cout << "Hello the Executor Service" << endl;
}



class MyFunctor {
public:
    void operator()() {
        cout << "Hello Multithreading" << endl;
    }
};



int main() {
    // INIT THE EXECUTOR SERVICE WITH 2 THREADS
    auto execService = mylib::ExecService(2);


    // SUBMIT
    execService.submit([] { cout << "Hello World" << endl; });

    execService.submit(&doTask);

    execService.submit(MyFunctor());


    // WAIT FOR THE COMPLETION OF ALL TASKS AND SHUTDOWN EXECUTOR SERVICE
    execService.waitTaskDone();
    execService.shutdown();

    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo11b-exec-service.cpp
================================================
/*
EXECUTOR SERVICES AND THREAD POOLS

Executor services in C++ POSIX threading are not supported by default.
So, I use mylib::ExecService for this demonstration.
*/


#include <iostream>
#include <unistd.h>
#include "mylib-execservice.hpp"
using namespace std;



int main() {
    constexpr int NUM_THREADS = 2;
    constexpr int NUM_TASKS = 5;

    auto execService = mylib::ExecService(NUM_THREADS);

    for (int i = 0; i < NUM_TASKS; ++i) {
        execService.submit([=] {
            char id = 'A' + i;
            cout << "Task " << id << " is starting" << endl;
            sleep(3);
            cout << "Task " << id << " is completed" << endl;
        });
    }

    cout << "All tasks are submitted" << endl;

    execService.waitTaskDone();
    cout << "All tasks are completed" << endl;

    execService.shutdown();

    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo12a-race-condition.cpp
================================================
/*
RACE CONDITIONS
*/


#include <iostream>
#include <pthread.h>
#include <unistd.h>
using namespace std;



void* doTask(void* arg) {
    int index = *(int*) arg;

    sleep(1);

    cout << index;

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    constexpr int NUM_THREADS = 4;

    pthread_t lstTid[NUM_THREADS];
    int lstArg[NUM_THREADS];

    int ret = 0;


    for (int i = 0; i < NUM_THREADS; ++i) {
        lstArg[i] = i;
        ret = pthread_create(&lstTid[i], nullptr, &doTask, &lstArg[i]);
    }

    for (auto&& tid : lstTid) {
        ret = pthread_join(tid, nullptr);
    }


    cout << endl;
    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo12b01-data-race-single.cpp
================================================
/*
DATA RACES
Version 01: Without multithreading
*/


#include <iostream>
#include <cstdlib>
using namespace std;



int *a = nullptr;
int N = 0;



int getResult() {
    a = (int*)calloc(sizeof(int), N + 1);

    for (int i = 1; i <= N; ++i)
        if (0 == i % 2 || 0 == i % 3)
            a[i] = 1;

    int result = 0;

    for (int i = 1; i <= N; ++i)
        if (a[i])
            ++result;

    free(a);
    a = nullptr;

    return result;
}



int main() {
    N = 8;

    int result = getResult();

    cout << "Numbers of integers that are divisible by 2 or 3 is: " << result << endl;
    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo12b02-data-race-multi.cpp
================================================
/*
DATA RACES
Version 02: Multithreading
*/


#include <iostream>
#include <cstdlib>
#include <pthread.h>
using namespace std;



int* a = nullptr;
int N = 0;



void* markDiv2(void*) {
    for (int i = 2; i <= N; i += 2)
        a[i] = 1;

    pthread_exit(nullptr);
    return nullptr;
}



void* markDiv3(void*) {
    for (int i = 3; i <= N; i += 3)
        a[i] = 1;

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    N = 8;

    pthread_t tidDiv2, tidDiv3;
    int ret = 0;

    a = (int*)calloc(sizeof(int), N + 1);

    ret = pthread_create(&tidDiv2, nullptr, &markDiv2, nullptr);
    ret = pthread_create(&tidDiv3, nullptr, &markDiv3, nullptr);
    ret = pthread_join(tidDiv2, nullptr);
    ret = pthread_join(tidDiv3, nullptr);

    int result = 0;

    for (int i = 1; i <= N; ++i)
        if (a[i])
            ++result;

    free(a);
    a = nullptr;

    cout << "Numbers of integers that are divisible by 2 or 3 is: " << result << endl;
    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo12bex-data-race-fork.cpp
================================================
/*
DATA RACES
*/


#include <iostream>
#include <fstream>
#include <unistd.h>
using namespace std;



int main() {
    int pid = 0;

    pid = fork();

    if (-1 == pid) {
        cerr << "Cannot fork" << endl;
        return 1;
    }


    ofstream ofs;
    ofs.open("tmp-output.txt");

    if (ofs.fail()) {
        return 1;
    }

    cout << "Writing to the file..." << endl;

    ofs << pid << endl;

    ofs.close();
    return 0;
}


/*
The content of the file is UNKNOWN.
It may be:
    0

or
    34

or
    0
    34

or
    34
    0

Assume that 34 and 0 are process ids.
*/


================================================
FILE: cpp/cpp-pthread/demo12c01-race-cond-data-race.cpp
================================================
/*
RACE CONDITIONS AND DATA RACES
*/


#include <iostream>
#include <unistd.h>
#include <pthread.h>
using namespace std;



int counter = 0;



void* increaseCounter(void*) {
    sleep(1);

    for (int i = 0; i < 1000; ++i) {
        counter += 1;
    }

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    constexpr int NUM_THREADS = 16;
    pthread_t lstTid[NUM_THREADS];
    int ret = 0;

    for (int i = 0; i < NUM_THREADS; ++i) {
        ret = pthread_create(&lstTid[i], nullptr, &increaseCounter, nullptr);
    }

    for (int i = 0; i < NUM_THREADS; ++i) {
        ret = pthread_join(lstTid[i], nullptr);
    }

    cout << "counter = " << counter << endl;
    // We are NOT sure that counter = 16000

    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo12c02-race-cond-data-race.cpp
================================================
/*
RACE CONDITIONS AND DATA RACES
*/


#include <iostream>
#include <pthread.h>
#include <unistd.h>
using namespace std;



int counter = 0;



void* doTaskA(void*) {
    sleep(1);

    while (counter < 10)
        ++counter;

    cout << "A won !!!" << endl;

    pthread_exit(nullptr);
    return nullptr;
}



void* doTaskB(void*) {
    sleep(1);

    while (counter > -10)
        --counter;

    cout << "B won !!!" << endl;

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    pthread_t tidA, tidB;
    int ret = 0;

    ret = pthread_create(&tidA, nullptr, &doTaskA, nullptr);
    ret = pthread_create(&tidB, nullptr, &doTaskB, nullptr);

    ret = pthread_join(tidA, nullptr);
    ret = pthread_join(tidB, nullptr);

    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo13a-mutex.cpp
================================================
/*
MUTEXES
*/


#include <iostream>
#include <unistd.h>
#include <pthread.h>
using namespace std;



pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
int counter = 0;



void* doTask(void*) {
    sleep(1);

    pthread_mutex_lock(&mut);

    for (int i = 0; i < 1000; ++i)
        ++counter;

    pthread_mutex_unlock(&mut);

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    constexpr int NUM_THREADS = 16;
    pthread_t lstTid[NUM_THREADS];
    int ret = 0;

    for (auto&& tid : lstTid) {
        ret = pthread_create(&tid, nullptr, &doTask, nullptr);
    }

    for (auto&& tid : lstTid) {
        ret = pthread_join(tid, nullptr);
    }

    cout << "counter = " << counter << endl;
    // We are sure that counter = 16000

    ret = pthread_mutex_destroy(&mut);
    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo13b-mutex-trylock.cpp
================================================
/*
MUTEXES
Locking with a nonblocking mutex

Use pthread_mutex_trylock to attempt to lock the mutex pointed to by mutex.
*/


#include <iostream>
#include <pthread.h>
#include <unistd.h>
using namespace std;



pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
int counter = 0;



void* doTask(void*) {
    int ret = 0;
    sleep(1);

    ret = pthread_mutex_trylock(&mut);

    if (ret) {
        /*
        switch (ret) {
            case EBUSY:
                The mutex could not be acquired because the mutex pointed to by mutex
                was already locked.

            case EAGAIN:
                The mutex could not be acquired because the maximum number
                of recursive locks for mutex has been exceeded.

            case EOWNERDEAD:
                The last owner of this mutex died while holding the mutex.
                This mutex is now owned by the caller.
                The caller must attempt to make the state protected by the mutex consistent.

            case ENOTRECOVERABLE:
                The mutex you are trying to acquire is protecting state left irrecoverable
                by the mutex's previous owner that died while holding the lock.
                The mutex has not been acquired.
                This condition can occur when the lock was previously acquired
                with EOWNERDEAD and the owner was unable to cleanup the state and
                had unlocked the mutex without making the mutex state consistent.

            case ENOMEM:
                The limit on the number of simultaneously held mutexes has been exceeded.
        }
        */

        pthread_exit(nullptr);
        return nullptr;
    }

    for (int i = 0; i < 10000; ++i)
        ++counter;

    pthread_mutex_unlock(&mut);

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    constexpr int NUM_THREADS = 3;
    pthread_t lstTid[NUM_THREADS];
    int ret = 0;

    for (auto&& tid : lstTid) {
        ret = pthread_create(&tid, nullptr, &doTask, nullptr);
    }

    for (auto&& tid : lstTid) {
        ret = pthread_join(tid, nullptr);
    }

    cout << "counter = " << counter << endl;
    // counter can be 10000, 20000 or 30000

    ret = pthread_mutex_destroy(&mut);
    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo14-synchronized-block.cpp
================================================
/*
SYNCHRONIZED BLOCKS

Synchronized blocks in C++ POSIX threading are not supported by default.
To demonstate synchronized blocks, I implement the class LockGuard.

Now, let's see the code:
    {
        LockGuard lk(&mutex);
        // Do something in the critical section
    }

When go to the end of the code block, lk object shall execute it's destructor and release mutex.
*/


#include <iostream>
#include <unistd.h>
#include <pthread.h>
using namespace std;



class LockGuard {

private:
    pthread_mutex_t* mut = nullptr;

private:
    LockGuard(const LockGuard&) = delete;
    LockGuard(const LockGuard&&) = delete;
    void operator=(const LockGuard&) = delete;
    void operator=(const LockGuard&&) = delete;

public:
    LockGuard(pthread_mutex_t* mut) {
        this->mut = mut; // Assume that mut != nullptr
        pthread_mutex_lock(this->mut);
    }

    ~LockGuard() {
        pthread_mutex_unlock(this->mut);
    }

};



pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
int counter = 0;



void* doTask(void*) {
    sleep(1);

    // This is the "synchronized block"
    {
        LockGuard lk(&mut);

        for (int i = 0; i < 1000; ++i)
            ++counter;
    }

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    constexpr int NUM_THREADS = 16;
    pthread_t lstTid[NUM_THREADS];
    int ret = 0;

    for (auto&& tid : lstTid) {
        ret = pthread_create(&tid, nullptr, &doTask, nullptr);
    }

    for (auto&& tid : lstTid) {
        ret = pthread_join(tid, nullptr);
    }

    cout << "counter = " << counter << endl;
    // We are sure that counter = 16000

    ret = pthread_mutex_destroy(&mut);
    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo15a-deadlock.cpp
================================================
/*
DEADLOCK
Version A
*/


#include <iostream>
#include <pthread.h>
using namespace std;



pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;



void* doTask(void* arg) {
    auto name = (const char*) arg;

    pthread_mutex_lock(&mut);

    cout << name << " acquired resource" << endl;

    // pthread_mutex_unlock(&mut); // Forget this statement ==> deadlock

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    pthread_t tidFoo, tidBar;
    int ret = 0;

    ret = pthread_create(&tidFoo, nullptr, &doTask, (void*)"foo");
    ret = pthread_create(&tidBar, nullptr, &doTask, (void*)"bar");

    ret = pthread_join(tidFoo, nullptr);
    ret = pthread_join(tidBar, nullptr);

    cout << "You will never see this statement due to deadlock!" << endl;
    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo15b-deadlock.cpp
================================================
/*
DEADLOCK
Version B
*/


#include <iostream>
#include <unistd.h>
#include <pthread.h>
using namespace std;



pthread_mutex_t mutResourceA = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutResourceB = PTHREAD_MUTEX_INITIALIZER;



void* foo(void*) {
    pthread_mutex_lock(&mutResourceA);
    cout << "foo acquired resource A" << endl;

    sleep(1);

    pthread_mutex_lock(&mutResourceB);
    cout << "foo acquired resource B" << endl;
    pthread_mutex_unlock(&mutResourceB);

    pthread_mutex_unlock(&mutResourceA);

    pthread_exit(nullptr);
    return nullptr;
}



void* bar(void*) {
    pthread_mutex_lock(&mutResourceB);
    cout << "bar acquired resource B" << endl;

    sleep(1);

    pthread_mutex_lock(&mutResourceA);
    cout << "bar acquired resource A" << endl;
    pthread_mutex_unlock(&mutResourceA);

    pthread_mutex_unlock(&mutResourceB);

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    pthread_t tidFoo, tidBar;
    int ret = 0;

    ret = pthread_create(&tidFoo, nullptr, &foo, nullptr);
    ret = pthread_create(&tidBar, nullptr, &bar, nullptr);

    ret = pthread_join(tidFoo, nullptr);
    ret = pthread_join(tidBar, nullptr);

    ret = pthread_mutex_destroy(&mutResourceA);
    ret = pthread_mutex_destroy(&mutResourceB);

    cout << "You will never see this statement due to deadlock!" << endl;
    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo16-monitor.cpp
================================================
/*
MONITORS
Implementation of a monitor for managing a counter
*/


#include <iostream>
#include <unistd.h>
#include <pthread.h>
using namespace std;



class Monitor {
private:
    pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
    int* pCounter = nullptr;


public:
    // Should disable copy/move constructors, copy/move assignment operators


    void init(int* pCounter) {
        destroy();
        mut = PTHREAD_MUTEX_INITIALIZER;
        this->pCounter = pCounter;
    }


    void increaseCounter() {
        int ret = 0;
        ret = pthread_mutex_lock(&mut);
        (*pCounter) += 1;
        ret = pthread_mutex_unlock(&mut);
    }


    void destroy() {
        pthread_mutex_destroy(&mut);
    }
};



void* doTask(void* arg) {
    auto monitor = (Monitor*) arg;

    sleep(1);

    for (int i = 0; i < 1000; ++i)
        monitor->increaseCounter();

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    int counter = 0;
    Monitor monitor;

    constexpr int NUM_THREADS = 16;
    pthread_t lstTid[NUM_THREADS];

    int ret = 0;

    monitor.init(&counter);

    for (auto&& tid : lstTid) {
        ret = pthread_create(&tid, nullptr, &doTask, &monitor);
    }

    for (auto&& tid : lstTid) {
        ret = pthread_join(tid, nullptr);
    }

    monitor.destroy();

    cout << "counter = " << counter << endl;
    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo17a-reentrant-lock.cpp
================================================
/*
REENTRANT LOCKS (RECURSIVE MUTEXES)
Version A: Introduction to reentrant locks
*/


#include <iostream>
#include <pthread.h>
using namespace std;



pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;



void* doTask(void*) {
    pthread_mutex_lock(&mut);
    cout << "First time acquiring the resource" << endl;

    pthread_mutex_lock(&mut);
    cout << "Second time acquiring the resource" << endl;

    pthread_mutex_unlock(&mut);
    pthread_mutex_unlock(&mut);

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    pthread_t tid;
    int ret = 0;

    ret = pthread_create(&tid, nullptr, &doTask, nullptr);

    /*
    The thread tid shall meet deadlock.
    So, you will never get output "Second time acquiring the resource".
    */

    ret = pthread_join(tid, nullptr);

    ret = pthread_mutex_destroy(&mut);

    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo17b-reentrant-lock.cpp
================================================
/*
REENTRANT LOCKS (RECURSIVE MUTEXES)
Version B: Solving the problem from version A
*/


#include <iostream>
#include <pthread.h>
using namespace std;



pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;



void* doTask(void*) {
    pthread_mutex_lock(&mut);
    cout << "First time acquiring the resource" << endl;

    pthread_mutex_lock(&mut);
    cout << "Second time acquiring the resource" << endl;

    pthread_mutex_unlock(&mut);
    pthread_mutex_unlock(&mut);

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    pthread_t tid;
    pthread_mutexattr_t attr;
    int ret = 0;

    ret = pthread_mutexattr_init(&attr);
    ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
    ret = pthread_mutex_init(&mut, &attr);

    ret = pthread_create(&tid, nullptr, &doTask, nullptr);
    ret = pthread_join(tid, nullptr);

    ret = pthread_mutexattr_destroy(&attr);
    ret = pthread_mutex_destroy(&mut);

    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo17c-reentrant-lock.cpp
================================================
/*
REENTRANT LOCKS (RECURSIVE MUTEXES)
Version C: A multithreaded app example
*/


#include <iostream>
#include <unistd.h>
#include <pthread.h>
using namespace std;



pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;



void* doTask(void* arg) {
    char name = *(char*) arg;
    sleep(1);

    pthread_mutex_lock(&mut);
    cout << "First time " << name << " acquiring the resource" << endl;

    pthread_mutex_lock(&mut);
    cout << "Second time " << name << " acquiring the resource" << endl;

    pthread_mutex_unlock(&mut);
    pthread_mutex_unlock(&mut);

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    constexpr int NUM_THREADS = 3;

    pthread_t lstTid[NUM_THREADS];
    char lstArg[NUM_THREADS];

    pthread_mutexattr_t attr;
    int ret = 0;

    ret = pthread_mutexattr_init(&attr);
    ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
    ret = pthread_mutex_init(&mut, &attr);

    for (int i = 0; i < NUM_THREADS; ++i) {
        lstArg[i] = char(i + 'A');
        ret = pthread_create(&lstTid[i], nullptr, &doTask, &lstArg[i]);
    }

    for (auto&& tid : lstTid) {
        ret = pthread_join(tid, nullptr);
    }

    pthread_mutexattr_destroy(&attr);
    pthread_mutex_destroy(&mut);

    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo18a01-barrier.cpp
================================================
/*
BARRIERS AND LATCHES
Version A: Cyclic barriers
*/


#include <iostream>
#include <string>
#include <tuple>
#include <unistd.h>
#include <pthread.h>
using namespace std;



pthread_barrier_t syncPoint;



void* processRequest(void* argVoid) {
    auto arg = *(tuple<string,int>*) argVoid;
    string userName = std::get<0>(arg);
    int waitTime = std::get<1>(arg);

    sleep(waitTime);

    cout << "Get request from " << userName << endl;
    pthread_barrier_wait(&syncPoint);

    cout << "Process request for " << userName << endl;
    pthread_barrier_wait(&syncPoint);

    cout << "Done " << userName << endl;

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    constexpr int NUM_THREADS = 3;
    pthread_t lstTid[NUM_THREADS];
    int ret = 0;

    // tuple<userName, waitTime>
    tuple<string,int> lstArg[NUM_THREADS] = {
        { "lorem", 1 },
        { "ipsum", 2 },
        { "dolor", 3 },
    };

    ret = pthread_barrier_init(&syncPoint, nullptr, 3); // participant count = 3

    for (int i = 0; i < NUM_THREADS; ++i) {
        ret = pthread_create(&lstTid[i], nullptr, &processRequest, &lstArg[i]);
    }

    for (auto&& tid : lstTid) {
        ret = pthread_join(tid, nullptr);
    }

    ret = pthread_barrier_destroy(&syncPoint);
    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo18a02-barrier.cpp
================================================
/*
BARRIERS AND LATCHES
Version A: Cyclic barriers
*/


#include <iostream>
#include <string>
#include <tuple>
#include <unistd.h>
#include <pthread.h>
using namespace std;



pthread_barrier_t syncPoint;



void* processRequest(void* argVoid) {
    auto arg = *(tuple<string,int>*) argVoid;
    string userName = std::get<0>(arg);
    int waitTime = std::get<1>(arg);

    sleep(waitTime);

    cout << "Get request from " << userName << endl;
    pthread_barrier_wait(&syncPoint);

    cout << "Process request for " << userName << endl;
    pthread_barrier_wait(&syncPoint);

    cout << "Done " << userName << endl;

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    constexpr int NUM_THREADS = 4;
    pthread_t lstTid[NUM_THREADS];
    int ret = 0;

    // tuple<userName, waitTime>
    tuple<string,int> lstArg[NUM_THREADS] = {
        { "lorem", 1 },
        { "ipsum", 3 },
        { "dolor", 3 },
        { "amet", 10 }
    };

    ret = pthread_barrier_init(&syncPoint, nullptr, 2); // participant count = 2

    for (int i = 0; i < NUM_THREADS; ++i) {
        ret = pthread_create(&lstTid[i], nullptr, &processRequest, &lstArg[i]);
    }

    // Thread with userName = "amet" shall be FREEZED

    for (auto&& tid : lstTid) {
        ret = pthread_join(tid, nullptr);
    }

    ret = pthread_barrier_destroy(&syncPoint);
    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo18a03-barrier.cpp
================================================
/*
BARRIERS AND LATCHES
Version A: Cyclic barriers
*/


#include <iostream>
#include <string>
#include <tuple>
#include <unistd.h>
#include <pthread.h>
using namespace std;



pthread_barrier_t syncPointA;
pthread_barrier_t syncPointB;



void* processRequest(void* argVoid) {
    auto arg = *(tuple<string,int>*) argVoid;
    string userName = std::get<0>(arg);
    int waitTime = std::get<1>(arg);

    sleep(waitTime);

    cout << "Get request from " << userName << endl;
    pthread_barrier_wait(&syncPointA);

    cout << "Process request for " << userName << endl;
    pthread_barrier_wait(&syncPointB);

    cout << "Done " << userName << endl;

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    constexpr int NUM_THREADS = 4;
    pthread_t lstTid[NUM_THREADS];
    int ret = 0;

    // tuple<userName, waitTime>
    tuple<string,int> lstArg[NUM_THREADS] = {
        { "lorem", 1 },
        { "ipsum", 3 },
        { "dolor", 3 },
        { "amet", 10 }
    };

    ret = pthread_barrier_init(&syncPointA, nullptr, 2);
    ret = pthread_barrier_init(&syncPointB, nullptr, 2);

    for (int i = 0; i < NUM_THREADS; ++i) {
        ret = pthread_create(&lstTid[i], nullptr, &processRequest, &lstArg[i]);
    }

    for (auto&& tid : lstTid) {
        ret = pthread_join(tid, nullptr);
    }

    ret = pthread_barrier_destroy(&syncPointA);
    ret = pthread_barrier_destroy(&syncPointB);
    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo18b01-latch.cpp
================================================
/*
BARRIERS AND LATCHES
Version B: Count-down latches

Count-down latches in C++ POSIX threading are not supported by default.
So, I use mylib::CountDownLatch for this demonstration.
*/


#include <iostream>
#include <string>
#include <tuple>
#include <unistd.h>
#include <pthread.h>
#include "mylib-latch.hpp"
using namespace std;



mylib::CountDownLatch syncPoint(3);



void* processRequest(void* argVoid) {
    auto arg = *(tuple<string,int>*) argVoid;
    string userName = std::get<0>(arg);
    int waitTime = std::get<1>(arg);

    sleep(waitTime);

    cout << "Get request from " << userName << endl;

    syncPoint.countDown();
    syncPoint.wait();

    cout << "Done " << userName << endl;

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    constexpr int NUM_THREADS = 3;
    pthread_t lstTid[NUM_THREADS];
    int ret = 0;

    // tuple<userName, waitTime>
    tuple<string,int> lstArg[NUM_THREADS] = {
        { "lorem", 1 },
        { "ipsum", 2 },
        { "dolor", 3 }
    };

    for (int i = 0; i < NUM_THREADS; ++i) {
        ret = pthread_create(&lstTid[i], nullptr, &processRequest, &lstArg[i]);
    }

    for (auto&& tid : lstTid) {
        ret = pthread_join(tid, nullptr);
    }

    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo18b02-latch.cpp
================================================
/*
BARRIERS AND LATCHES
Version B: Count-down latches

Main thread waits for 3 child threads to get enough data to progress.

Count-down latches in C++ POSIX threading are not supported by default.
So, I use mylib::CountDownLatch for this demonstration.
*/


#include <iostream>
#include <string>
#include <tuple>
#include <unistd.h>
#include <pthread.h>
#include "mylib-latch.hpp"
using namespace std;



constexpr int NUM_THREADS = 3;
mylib::CountDownLatch syncPoint(NUM_THREADS);



void* doTask(void* argVoid) {
    auto arg = *(tuple<string,int>*) argVoid;
    string message = std::get<0>(arg);
    int waitTime = std::get<1>(arg);

    sleep(waitTime);

    cout << message << endl;
    syncPoint.countDown();

    sleep(8);
    cout << "Cleanup" << endl;

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    pthread_t lstTid[NUM_THREADS];
    int ret = 0;

    // tuple<message, waitTime>
    tuple<string,int> lstArg[NUM_THREADS] = {
        { "Send request to egg.net to get data", 6 },
        { "Send request to foo.org to get data", 2 },
        { "Send request to bar.com to get data", 4 }
    };

    for (int i = 0; i < NUM_THREADS; ++i) {
        ret = pthread_create(&lstTid[i], nullptr, &doTask, &lstArg[i]);
    }

    syncPoint.wait();
    cout << "\nNow we have enough data to progress to next step\n" << endl;

    for (auto&& tid : lstTid) {
        ret = pthread_join(tid, nullptr);
    }

    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo19-read-write-lock.cpp
================================================
/*
READ-WRITE LOCKS

Lock for reading
    A thread can hold multiple concurrent read locks on the rwlock object
    (that is, successfully call the pthread_rwlock_rdlock subroutine n times).
    If so, the thread must perform matching unlocks
    (that is, it must call the pthread_rwlock_unlock subroutine n times).

    There is a function that supports non-blocking:
        pthread_rwlock_tryrdlock

Lock for writing
    The pthread_rwlock_wrlock subroutine applies a write lock to the read/write lock
    referenced by the rwlock object.
    The calling thread acquires the write lock if no other thread (reader or writer)
    holds the read/write lock on the rwlock object.
    Otherwise, the thread does not return from the pthread_rwlock_wrlock call
    until it can acquire the lock.

    There is a function that supports non-blocking:
        pthread_rwlock_trywrlock
*/


#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include "../cpp-std/mylib-random.hpp"
using namespace std;



volatile int resource = 0;
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;



void* readFunc(void* arg) {
    auto waitTime = *(int*) arg;
    sleep(waitTime);

    pthread_rwlock_rdlock(&rwlock);

    cout << "read: " << resource << endl;

    pthread_rwlock_unlock(&rwlock);

    pthread_exit(nullptr);
    return nullptr;
}



void* writeFunc(void* arg) {
    auto waitTime = *(int*) arg;
    sleep(waitTime);

    pthread_rwlock_wrlock(&rwlock);

    resource = mylib::RandInt::get(100);
    cout << "write: " << resource << endl;

    pthread_rwlock_unlock(&rwlock);

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    constexpr int NUM_THREADS_READ = 10;
    constexpr int NUM_THREADS_WRITE = 4;
    constexpr int NUM_ARGS = 3;

    pthread_t lstTidRead[NUM_THREADS_READ];
    pthread_t lstTidWrite[NUM_THREADS_WRITE];
    int lstArg[NUM_ARGS];
    int ret = 0;


    // INITIALIZE
    for (int i = 0; i < NUM_ARGS; ++i) {
        lstArg[i] = i;
    }


    // CREATE THREADS
    for (auto&& tid : lstTidRead) {
        int argIndex = mylib::RandInt::get(NUM_ARGS);
        ret = pthread_create(&tid, nullptr, &readFunc, &lstArg[argIndex]);
    }

    for (auto&& tid : lstTidWrite) {
        int argIndex = mylib::RandInt::get(NUM_ARGS);
        ret = pthread_create(&tid, nullptr, &writeFunc, &lstArg[argIndex]);
    }


    // JOIN THREADS
    for (auto&& tid : lstTidRead) {
        ret = pthread_join(tid, nullptr);
    }

    for (auto&& tid : lstTidWrite) {
        ret = pthread_join(tid, nullptr);
    }


    pthread_rwlock_destroy(&rwlock);
    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo20a01-semaphore.cpp
================================================
/*
SEMAPHORES
Version A: Paper sheets and packages
*/


#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
using namespace std;



sem_t semPackage;



void* makeOneSheet(void*) {
    for (int i = 0; i < 4; ++i) {
        cout << "Make 1 sheet" << endl;
        sleep(1);
        sem_post(&semPackage);
    }

    pthread_exit(nullptr);
    return nullptr;
}



void* combineOnePackage(void*) {
    for (int i = 0; i < 4; ++i) {
        sem_wait(&semPackage);
        sem_wait(&semPackage);
        cout << "Combine 2 sheets into 1 package" << endl;
    }

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    pthread_t tidMakeSheetA, tidMakeSheetB, tidCombinePackage;
    int ret = 0;

    ret = sem_init(&semPackage, 0, 0);

    ret = pthread_create(&tidMakeSheetA, nullptr, &makeOneSheet, nullptr);
    ret = pthread_create(&tidMakeSheetB, nullptr, &makeOneSheet, nullptr);
    ret = pthread_create(&tidCombinePackage, nullptr, &combineOnePackage, nullptr);

    ret = pthread_join(tidMakeSheetA, nullptr);
    ret = pthread_join(tidMakeSheetB, nullptr);
    ret = pthread_join(tidCombinePackage, nullptr);

    ret = sem_destroy(&semPackage);
    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo20a02-semaphore.cpp
================================================
/*
SEMAPHORES
Version A: Paper sheets and packages
*/


#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
using namespace std;



sem_t semPackage;
sem_t semSheet;



void* makeOneSheet(void*) {
    for (int i = 0; i < 4; ++i) {
        sem_wait(&semSheet);
        cout << "Make 1 sheet" << endl;
        sem_post(&semPackage);
    }

    pthread_exit(nullptr);
    return nullptr;
}



void* combineOnePackage(void*) {
    for (int i = 0; i < 4; ++i) {
        sem_wait(&semPackage);
        sem_wait(&semPackage);

        cout << "Combine 2 sheets into 1 package" << endl;
        sleep(2);

        sem_post(&semSheet);
        sem_post(&semSheet);
    }

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    pthread_t tidMakeSheetA, tidMakeSheetB, tidCombinePackage;
    int ret = 0;

    ret = sem_init(&semPackage, 0, 0);
    ret = sem_init(&semSheet, 0, 2);

    ret = pthread_create(&tidMakeSheetA, nullptr, &makeOneSheet, nullptr);
    ret = pthread_create(&tidMakeSheetB, nullptr, &makeOneSheet, nullptr);
    ret = pthread_create(&tidCombinePackage, nullptr, &combineOnePackage, nullptr);

    ret = pthread_join(tidMakeSheetA, nullptr);
    ret = pthread_join(tidMakeSheetB, nullptr);
    ret = pthread_join(tidCombinePackage, nullptr);

    ret = sem_destroy(&semPackage);
    ret = sem_destroy(&semSheet);

    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo20a03-semaphore-deadlock.cpp
================================================
/*
SEMAPHORES
Version A: Paper sheets and packages
*/


#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
using namespace std;



sem_t semPackage;
sem_t semSheet;



void* makeOneSheet(void*) {
    for (int i = 0; i < 4; ++i) {
        sem_wait(&semSheet);
        cout << "Make 1 sheet" << endl;
        sem_post(&semPackage);
    }

    pthread_exit(nullptr);
    return nullptr;
}



void* combineOnePackage(void*) {
    for (int i = 0; i < 4; ++i) {
        sem_wait(&semPackage);
        sem_wait(&semPackage);

        cout << "Combine 2 sheets into 1 package" << endl;
        sleep(2);

        sem_post(&semSheet);
        // Missing one statement: sem_post(&semSheet) ==> deadlock
    }

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    pthread_t tidMakeSheetA, tidMakeSheetB, tidCombinePackage;
    int ret = 0;

    ret = sem_init(&semPackage, 0, 0);
    ret = sem_init(&semSheet, 0, 2);

    ret = pthread_create(&tidMakeSheetA, nullptr, &makeOneSheet, nullptr);
    ret = pthread_create(&tidMakeSheetB, nullptr, &makeOneSheet, nullptr);
    ret = pthread_create(&tidCombinePackage, nullptr, &combineOnePackage, nullptr);

    ret = pthread_join(tidMakeSheetA, nullptr);
    ret = pthread_join(tidMakeSheetB, nullptr);
    ret = pthread_join(tidCombinePackage, nullptr);

    ret = sem_destroy(&semPackage);
    ret = sem_destroy(&semSheet);

    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo20b-semaphore.cpp
================================================
/*
SEMAPHORES
Version B: Tires and chassis
*/


#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
using namespace std;



sem_t semTire;
sem_t semChassis;



void* makeTire(void*) {
    int ret = 0;

    for (int i = 0; i < 8; ++i) {
        sem_wait(&semTire);

        cout << "Make 1 tire" << endl;
        sleep(1);

        sem_post(&semChassis);
    }

    pthread_exit(nullptr);
    return nullptr;
}



void* makeChassis(void*) {
    for (int i = 0; i < 4; ++i) {
        sem_wait(&semChassis);
        sem_wait(&semChassis);
        sem_wait(&semChassis);
        sem_wait(&semChassis);

        cout << "Make 1 chassis" << endl;
        sleep(3);

        sem_post(&semTire);
        sem_post(&semTire);
        sem_post(&semTire);
        sem_post(&semTire);
    }

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    pthread_t tidTireA, tidTireB, tidChassis;
    int ret = 0;

    ret = sem_init(&semTire, 0, 4);
    ret = sem_init(&semChassis, 0, 0);

    ret = pthread_create(&tidTireA, nullptr, &makeTire, nullptr);
    ret = pthread_create(&tidTireB, nullptr, &makeTire, nullptr);
    ret = pthread_create(&tidChassis, nullptr, &makeChassis, nullptr);

    ret = pthread_join(tidTireA, nullptr);
    ret = pthread_join(tidTireB, nullptr);
    ret = pthread_join(tidChassis, nullptr);

    ret = sem_destroy(&semTire);
    ret = sem_destroy(&semChassis);

    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo21a01-condition-variable.cpp
================================================
/*
CONDITION VARIABLES
*/


#include <iostream>
#include <unistd.h>
#include <pthread.h>
using namespace std;



pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t conditionVar = PTHREAD_COND_INITIALIZER;



void* foo(void*) {
    cout << "foo is waiting..." << endl;

    pthread_mutex_lock(&mut);
    pthread_cond_wait(&conditionVar, &mut);

    cout << "foo resumed" << endl;

    pthread_mutex_unlock(&mut);

    pthread_exit(nullptr);
    return nullptr;
}



void* bar(void*) {
    sleep(3);
    pthread_cond_signal(&conditionVar);

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    pthread_t tidFoo, tidBar;
    int ret = 0;

    ret = pthread_create(&tidFoo, nullptr, &foo, nullptr);
    ret = pthread_create(&tidBar, nullptr, &bar, nullptr);

    ret = pthread_join(tidFoo, nullptr);
    ret = pthread_join(tidBar, nullptr);

    ret = pthread_cond_destroy(&conditionVar);
    ret = pthread_mutex_destroy(&mut);

    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo21a02-condition-variable.cpp
================================================
/*
CONDITION VARIABLES
*/


#include <iostream>
#include <unistd.h>
#include <pthread.h>
using namespace std;



pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t conditionVar = PTHREAD_COND_INITIALIZER;

constexpr int NUM_TH_FOO = 3;



void* foo(void*) {
    cout << "foo is waiting..." << endl;

    pthread_mutex_lock(&mut);
    pthread_cond_wait(&conditionVar, &mut);

    cout << "foo resumed" << endl;

    pthread_mutex_unlock(&mut);

    pthread_exit(nullptr);
    return nullptr;
}



void* bar(void*) {
    for (int i = 0; i < NUM_TH_FOO; ++i) {
        sleep(2);
        pthread_cond_signal(&conditionVar);
    }

    pthread_exit(nullptr);
    return nullptr;
}



int main() {
    pthread_t lstTidFoo[NUM_TH_FOO];
    pthread_t tidBar;

    int ret = 0;

    for (auto&& tidFoo : lstTidFoo) {
        ret = pthread_create(&tidFoo, nullptr, &foo, nullptr);
    }

    ret = pthread_create(&tidBar, nullptr, &bar, nullptr);

    for (auto&& tidFoo : lstTidFoo) {
        ret = pthread_join(tidFoo, nullptr);
    }

    ret = pthread_join(tidBar, nullptr);

    ret = pthread_cond_destroy(&conditionVar);
    ret = pthread_mutex_destroy(&mut);

    return 0;
}


================================================
FILE: cpp/cpp-pthread/demo21a03-condition-variable.cpp
================================================
/*
CONDITION VARIABLES
*/


#include <iostream>
#include <unistd.h>
#include <pthread.h>
using namespace std;



pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t conditionVar = PTHREAD_COND_INITIALIZER;

constexpr int NUM_TH_FOO = 3;



void* foo(void*) {
    cout << "foo is waiting..." << endl;

    pthread_mutex_lock(&mut);
    pthread_cond_wait(&conditionVar, &mut);

    cout << "foo resumed" << endl;

    pthread_mutex_unlock(&mut);

    pthread_exit(nullptr);
    return nullptr;
}



void* bar(void*) {
    sleep(3);
    // Notify all 
Download .txt
gitextract_mqx2volu/

├── .gitignore
├── LICENSE.txt
├── README.md
├── cpp/
│   ├── .gitignore
│   ├── README.md
│   ├── cpp-boost/
│   │   ├── demo00.cpp
│   │   ├── demo01a01-hello.cpp
│   │   ├── demo01a02-hello.cpp
│   │   ├── demo01b-hello-class01.cpp
│   │   ├── demo01b-hello-class02.cpp
│   │   ├── demo01b-hello-class03.cpp
│   │   ├── demo01b-hello-functor.cpp
│   │   ├── demo02-join.cpp
│   │   ├── demo03a-pass-arg.cpp
│   │   ├── demo03b-pass-arg.cpp
│   │   ├── demo03c-pass-arg.cpp
│   │   ├── demo04a-sleep.cpp
│   │   ├── demo04b-sleep.cpp
│   │   ├── demo05-id.cpp
│   │   ├── demo06a-list-threads.cpp
│   │   ├── demo06b-list-threads.cpp
│   │   ├── demo06c-list-threads.cpp
│   │   ├── demo07-terminate.cpp
│   │   ├── demo08-return-value.cpp
│   │   ├── demo09-detach.cpp
│   │   ├── demo10-yield.cpp
│   │   ├── demo11a-exec-service.cpp
│   │   ├── demo11b-exec-service.cpp
│   │   ├── demo12a-race-condition.cpp
│   │   ├── demo12b01-data-race-single.cpp
│   │   ├── demo12b02-data-race-multi.cpp
│   │   ├── demo12c01-race-cond-data-race.cpp
│   │   ├── demo12c02-race-cond-data-race.cpp
│   │   ├── demo13a-mutex.cpp
│   │   ├── demo13b01-mutex.cpp
│   │   ├── demo13b02-mutex.cpp
│   │   ├── demo13c-mutex-trylock.cpp
│   │   ├── demo14-synchronized-block.cpp
│   │   ├── demo15a-deadlock.cpp
│   │   ├── demo15b-deadlock.cpp
│   │   ├── demo16-monitor.cpp
│   │   ├── demo17a-reentrant-lock.cpp
│   │   ├── demo17b-reentrant-lock.cpp
│   │   ├── demo17c-reentrant-lock.cpp
│   │   ├── demo18a01-barrier.cpp
│   │   ├── demo18a02-barrier.cpp
│   │   ├── demo18a03-barrier.cpp
│   │   ├── demo18b01-latch.cpp
│   │   ├── demo18b02-latch.cpp
│   │   ├── demo19a-read-write-lock.cpp
│   │   ├── demo19b-read-write-lock.cpp
│   │   ├── demo20a01-semaphore.cpp
│   │   ├── demo20a02-semaphore.cpp
│   │   ├── demo20a03-semaphore-deadlock.cpp
│   │   ├── demo20b-semaphore.cpp
│   │   ├── demo21a01-condition-variable.cpp
│   │   ├── demo21a02-condition-variable.cpp
│   │   ├── demo21a03-condition-variable.cpp
│   │   ├── demo21b-condition-variable.cpp
│   │   ├── demo22a-blocking-queue.cpp
│   │   ├── demo22b-blocking-queue.cpp
│   │   ├── demo23a-thread-local.cpp
│   │   ├── demo23b-thread-local.cpp
│   │   ├── demo24-volatile.cpp
│   │   ├── demo25a-atomic.cpp
│   │   ├── demo25b-atomic.cpp
│   │   ├── demoex-async-future.cpp
│   │   ├── exer01a-max-div.cpp
│   │   ├── exer01b-max-div.cpp
│   │   ├── exer01c-max-div.cpp
│   │   ├── exer02a01-producer-consumer.cpp
│   │   ├── exer02a02-producer-consumer.cpp
│   │   ├── exer02a03-producer-consumer.cpp
│   │   ├── exer02a04-producer-consumer.cpp
│   │   ├── exer02b01-producer-consumer.cpp
│   │   ├── exer02b02-producer-consumer.cpp
│   │   ├── exer02b03-producer-consumer.cpp
│   │   ├── exer02b04-producer-consumer.cpp
│   │   ├── exer02c-producer-consumer.cpp
│   │   ├── exer03a-readers-writers.cpp
│   │   ├── exer03b-readers-writers.cpp
│   │   ├── exer04-dining-philosophers.cpp
│   │   ├── exer05-util.hpp
│   │   ├── exer05a-product-matrix-vector.cpp
│   │   ├── exer05b-product-matrix-matrix.cpp
│   │   ├── exer06a-blocking-queue.cpp
│   │   ├── exer06b01-blocking-queue.cpp
│   │   ├── exer06b02-blocking-queue.cpp
│   │   ├── exer07a-data-server.cpp
│   │   ├── exer07b-data-server.cpp
│   │   ├── exer07c-data-server.cpp
│   │   ├── exer07d-data-server.cpp
│   │   ├── exer08-exec-service-itask.hpp
│   │   ├── exer08-exec-service-main.cpp
│   │   ├── exer08-exec-service-v0a.hpp
│   │   ├── exer08-exec-service-v0b.hpp
│   │   ├── exer08-exec-service-v1a.hpp
│   │   ├── exer08-exec-service-v1b.hpp
│   │   ├── exer08-exec-service-v2a.hpp
│   │   ├── exer08-exec-service-v2b.hpp
│   │   ├── mylib-blockingqueue.hpp
│   │   ├── mylib-random.hpp
│   │   ├── mylib-semaphore.hpp
│   │   └── mylib-time.hpp
│   ├── cpp-pthread/
│   │   ├── demo00.cpp
│   │   ├── demo01-hello.cpp
│   │   ├── demo02-join.cpp
│   │   ├── demo03a01-pass-arg.cpp
│   │   ├── demo03a02-pass-arg.cpp
│   │   ├── demo03b01-pass-arg.cpp
│   │   ├── demo03b02-pass-arg.cpp
│   │   ├── demo04-sleep.cpp
│   │   ├── demo05-id.cpp
│   │   ├── demo06a-list-threads.cpp
│   │   ├── demo06b-list-threads.cpp
│   │   ├── demo07a-terminate.cpp
│   │   ├── demo07b-terminate.cpp
│   │   ├── demo08a-return-value.cpp
│   │   ├── demo08b-return-value.cpp
│   │   ├── demo09a-detach.cpp
│   │   ├── demo09b-detach.cpp
│   │   ├── demo10-yield.cpp
│   │   ├── demo11a-exec-service.cpp
│   │   ├── demo11b-exec-service.cpp
│   │   ├── demo12a-race-condition.cpp
│   │   ├── demo12b01-data-race-single.cpp
│   │   ├── demo12b02-data-race-multi.cpp
│   │   ├── demo12bex-data-race-fork.cpp
│   │   ├── demo12c01-race-cond-data-race.cpp
│   │   ├── demo12c02-race-cond-data-race.cpp
│   │   ├── demo13a-mutex.cpp
│   │   ├── demo13b-mutex-trylock.cpp
│   │   ├── demo14-synchronized-block.cpp
│   │   ├── demo15a-deadlock.cpp
│   │   ├── demo15b-deadlock.cpp
│   │   ├── demo16-monitor.cpp
│   │   ├── demo17a-reentrant-lock.cpp
│   │   ├── demo17b-reentrant-lock.cpp
│   │   ├── demo17c-reentrant-lock.cpp
│   │   ├── demo18a01-barrier.cpp
│   │   ├── demo18a02-barrier.cpp
│   │   ├── demo18a03-barrier.cpp
│   │   ├── demo18b01-latch.cpp
│   │   ├── demo18b02-latch.cpp
│   │   ├── demo19-read-write-lock.cpp
│   │   ├── demo20a01-semaphore.cpp
│   │   ├── demo20a02-semaphore.cpp
│   │   ├── demo20a03-semaphore-deadlock.cpp
│   │   ├── demo20b-semaphore.cpp
│   │   ├── demo21a01-condition-variable.cpp
│   │   ├── demo21a02-condition-variable.cpp
│   │   ├── demo21a03-condition-variable.cpp
│   │   ├── demo21b-condition-variable.cpp
│   │   ├── demo22a-blocking-queue.cpp
│   │   ├── demo22b-blocking-queue.cpp
│   │   ├── demo23a-thread-local.cpp
│   │   ├── demo23b-thread-local.cpp
│   │   ├── demo24-volatile.cpp
│   │   ├── demo25a-atomic.c
│   │   ├── demo25b-atomic.c
│   │   ├── demoex-attribute.cpp
│   │   ├── demoex-oop.cpp
│   │   ├── demoex-signal.cpp
│   │   ├── exer01a-max-div.cpp
│   │   ├── exer01b-max-div.cpp
│   │   ├── exer01c-max-div.cpp
│   │   ├── exer02a01-producer-consumer.cpp
│   │   ├── exer02a02-producer-consumer.cpp
│   │   ├── exer02a03-producer-consumer.cpp
│   │   ├── exer02a04-producer-consumer.cpp
│   │   ├── exer02b01-producer-consumer.cpp
│   │   ├── exer02b02-producer-consumer.cpp
│   │   ├── exer02b03-producer-consumer.cpp
│   │   ├── exer02b04-producer-consumer.cpp
│   │   ├── exer02c-producer-consumer.cpp
│   │   ├── exer03a-readers-writers.cpp
│   │   ├── exer03b-readers-writers.cpp
│   │   ├── exer04-dining-philosophers.cpp
│   │   ├── exer05-util.hpp
│   │   ├── exer05a-product-matrix-vector.cpp
│   │   ├── exer05b-product-matrix-matrix.cpp
│   │   ├── exer06a-blocking-queue.cpp
│   │   ├── exer06b01-blocking-queue.cpp
│   │   ├── exer06b02-blocking-queue.cpp
│   │   ├── exer07a-data-server.cpp
│   │   ├── exer07b-data-server.cpp
│   │   ├── exer07c-data-server.cpp
│   │   ├── exer07d-data-server.cpp
│   │   ├── exer08-exec-service-itask.hpp
│   │   ├── exer08-exec-service-main.cpp
│   │   ├── exer08-exec-service-v0a.hpp
│   │   ├── exer08-exec-service-v0b.hpp
│   │   ├── exer08-exec-service-v1a.hpp
│   │   ├── exer08-exec-service-v1b.hpp
│   │   ├── exer08-exec-service-v2a.hpp
│   │   ├── exer08-exec-service-v2b.hpp
│   │   ├── exerex-countdown-timer-a.cpp
│   │   ├── exerex-countdown-timer-b.cpp
│   │   ├── mylib-blockingqueue.hpp
│   │   ├── mylib-execservice.hpp
│   │   └── mylib-latch.hpp
│   └── cpp-std/
│       ├── demo00.cpp
│       ├── demo01a01-hello.cpp
│       ├── demo01a02-hello.cpp
│       ├── demo01b-hello-class01.cpp
│       ├── demo01b-hello-class02.cpp
│       ├── demo01b-hello-class03.cpp
│       ├── demo01b-hello-functor.cpp
│       ├── demo01c-hello-lambda.cpp
│       ├── demo02-join.cpp
│       ├── demo03a-pass-arg.cpp
│       ├── demo03b-pass-arg.cpp
│       ├── demo03c-pass-arg.cpp
│       ├── demo04a-sleep.cpp
│       ├── demo04b-sleep.cpp
│       ├── demo05-id.cpp
│       ├── demo06a-list-threads.cpp
│       ├── demo06b-list-threads.cpp
│       ├── demo07-terminate.cpp
│       ├── demo08a-return-value.cpp
│       ├── demo08b-return-value.cpp
│       ├── demo08c-return-value.cpp
│       ├── demo09-detach.cpp
│       ├── demo10-yield.cpp
│       ├── demo11a-exec-service.cpp
│       ├── demo11b-exec-service.cpp
│       ├── demo12a-race-condition.cpp
│       ├── demo12b01-data-race-single.cpp
│       ├── demo12b02-data-race-multi.cpp
│       ├── demo12c01-race-cond-data-race.cpp
│       ├── demo12c02-race-cond-data-race.cpp
│       ├── demo13a-mutex.cpp
│       ├── demo13b01-mutex.cpp
│       ├── demo13b02-mutex.cpp
│       ├── demo13c-mutex-trylock.cpp
│       ├── demo14-synchronized-block.cpp
│       ├── demo15a-deadlock.cpp
│       ├── demo15b-deadlock.cpp
│       ├── demo16-monitor.cpp
│       ├── demo17a-reentrant-lock.cpp
│       ├── demo17b-reentrant-lock.cpp
│       ├── demo17c-reentrant-lock.cpp
│       ├── demo18a01-barrier.cpp
│       ├── demo18a02-barrier.cpp
│       ├── demo18a03-barrier.cpp
│       ├── demo18b01-latch.cpp
│       ├── demo18b02-latch.cpp
│       ├── demo19a-read-write-lock.cpp
│       ├── demo19b-read-write-lock.cpp
│       ├── demo20a01-semaphore.cpp
│       ├── demo20a02-semaphore.cpp
│       ├── demo20a03-semaphore-deadlock.cpp
│       ├── demo20b-semaphore.cpp
│       ├── demo21a01-condition-variable.cpp
│       ├── demo21a02-condition-variable.cpp
│       ├── demo21a03-condition-variable.cpp
│       ├── demo21b-condition-variable.cpp
│       ├── demo22a-blocking-queue.cpp
│       ├── demo22b-blocking-queue.cpp
│       ├── demo23a01-thread-local.cpp
│       ├── demo23a02-thread-local.cpp
│       ├── demo23b-thread-local.cpp
│       ├── demo24-volatile.cpp
│       ├── demo25a-atomic.cpp
│       ├── demo25b-atomic.cpp
│       ├── demo25c-atomic-gcc.cpp
│       ├── demoex-async-future.cpp
│       ├── demoex-jthread.cpp
│       ├── exer01a-max-div.cpp
│       ├── exer01b-max-div.cpp
│       ├── exer01c-max-div.cpp
│       ├── exer02a01-producer-consumer.cpp
│       ├── exer02a02-producer-consumer.cpp
│       ├── exer02a03-producer-consumer.cpp
│       ├── exer02a04-producer-consumer.cpp
│       ├── exer02b01-producer-consumer.cpp
│       ├── exer02b02-producer-consumer.cpp
│       ├── exer02b03-producer-consumer.cpp
│       ├── exer02b04-producer-consumer.cpp
│       ├── exer02c-producer-consumer.cpp
│       ├── exer03a-readers-writers.cpp
│       ├── exer03b-readers-writers.cpp
│       ├── exer04-dining-philosophers.cpp
│       ├── exer05-util.hpp
│       ├── exer05a-product-matrix-vector.cpp
│       ├── exer05b-product-matrix-matrix.cpp
│       ├── exer06a-blocking-queue.cpp
│       ├── exer06b01-blocking-queue.cpp
│       ├── exer06b02-blocking-queue.cpp
│       ├── exer07a-data-server.cpp
│       ├── exer07b-data-server.cpp
│       ├── exer07c-data-server.cpp
│       ├── exer07d-data-server.cpp
│       ├── exer08-exec-service-itask.hpp
│       ├── exer08-exec-service-main.cpp
│       ├── exer08-exec-service-v0a.hpp
│       ├── exer08-exec-service-v0b.hpp
│       ├── exer08-exec-service-v1a.hpp
│       ├── exer08-exec-service-v1b.hpp
│       ├── exer08-exec-service-v2a.hpp
│       ├── exer08-exec-service-v2b.hpp
│       ├── exerex-countdown-timer.cpp
│       ├── mylib-blockingqueue.hpp
│       ├── mylib-execservice.hpp
│       ├── mylib-random.hpp
│       └── mylib-time.hpp
├── csharp/
│   ├── .gitignore
│   ├── IRunnable.cs
│   ├── Program.cs
│   ├── demo/
│   │   ├── demo00-intro.cs
│   │   ├── demo01a-hello.cs
│   │   ├── demo01b01-hello.cs
│   │   ├── demo01b02-hello.cs
│   │   ├── demo01ex-name.cs
│   │   ├── demo02a-join.cs
│   │   ├── demo02b-join.cs
│   │   ├── demo03a-pass-arg.cs
│   │   ├── demo03b-pass-arg.cs
│   │   ├── demo03c-pass-arg.cs
│   │   ├── demo03d-pass-arg.cs
│   │   ├── demo04-sleep.cs
│   │   ├── demo05-id.cs
│   │   ├── demo06a-list-threads.cs
│   │   ├── demo06b-list-threads.cs
│   │   ├── demo07-terminate.cs
│   │   ├── demo08a-return-value.cs
│   │   ├── demo08b-return-value.cs
│   │   ├── demo09-detach.cs
│   │   ├── demo10-yield.cs
│   │   ├── demo11a01-exec-service.cs
│   │   ├── demo11a02-exec-service.cs
│   │   ├── demo11a03-exec-service.cs
│   │   ├── demo11a04-exec-service.cs
│   │   ├── demo11a05-exec-service.cs
│   │   ├── demo11b01-exec-service-parallel.cs
│   │   ├── demo11b02-exec-service-parallel.cs
│   │   ├── demo11c-exec-service.cs
│   │   ├── demo12a-race-condition.cs
│   │   ├── demo12b01-data-race-single.cs
│   │   ├── demo12b02-data-race-multi.cs
│   │   ├── demo12c01-race-cond-data-race.cs
│   │   ├── demo12c02-race-cond-data-race.cs
│   │   ├── demo13a-mutex.cs
│   │   ├── demo13b-mutex-trylock.cs
│   │   ├── demo14-synchronized-block.cs
│   │   ├── demo15a-deadlock.cs
│   │   ├── demo15b-deadlock.cs
│   │   ├── demo16-monitor.cs
│   │   ├── demo17a-reentrant-lock.cs
│   │   ├── demo17b-reentrant-lock.cs
│   │   ├── demo18a01-barrier.cs
│   │   ├── demo18a03-barrier.cs
│   │   ├── demo18b01-latch.cs
│   │   ├── demo18b02-latch.cs
│   │   ├── demo19-read-write-lock.cs
│   │   ├── demo20a01-semaphore.cs
│   │   ├── demo20a02-semaphore.cs
│   │   ├── demo20a03-semaphore-deadlock.cs
│   │   ├── demo20b-semaphore.cs
│   │   ├── demo21a01-condition-variable.cs
│   │   ├── demo21a02-condition-variable.cs
│   │   ├── demo21a03-condition-variable.cs
│   │   ├── demo21b-condition-variable.cs
│   │   ├── demo22a-blocking-queue.cs
│   │   ├── demo22b-blocking-queue.cs
│   │   ├── demo23a01-thread-local.cs
│   │   ├── demo23a02-thread-local.cs
│   │   ├── demo23b-thread-local.cs
│   │   ├── demo24-volatile.cs
│   │   ├── demo25a-atomic.cs
│   │   └── demo25b-atomic.cs
│   ├── demoex/
│   │   ├── demoex-async-future-a01.cs
│   │   ├── demoex-async-future-a02.cs
│   │   ├── demoex-async-future-a03.cs
│   │   ├── demoex-async-future-a04.cs
│   │   ├── demoex-async-future-a05.cs
│   │   ├── demoex-async-future-b01.cs
│   │   ├── demoex-async-future-b02.cs
│   │   ├── demoex-async-future-b03.cs
│   │   ├── demoex-async-future-b04.cs
│   │   ├── demoex-async-future-c01.cs
│   │   └── demoex-async-future-c02.cs
│   ├── exercise/
│   │   ├── exer01a-max-div.cs
│   │   ├── exer01b-max-div.cs
│   │   ├── exer01c-max-div.cs
│   │   ├── exer02a01-producer-consumer.cs
│   │   ├── exer02a02-producer-consumer.cs
│   │   ├── exer02a03-producer-consumer.cs
│   │   ├── exer02a04-producer-consumer.cs
│   │   ├── exer02b01-producer-consumer.cs
│   │   ├── exer02b02-producer-consumer.cs
│   │   ├── exer02b03-producer-consumer.cs
│   │   ├── exer02b04-producer-consumer.cs
│   │   ├── exer02c-producer-consumer.cs
│   │   ├── exer03a-readers-writers.cs
│   │   ├── exer03b-readers-writers.cs
│   │   ├── exer04a-dining-philosophers.cs
│   │   ├── exer04b-dining-philosophers.cs
│   │   ├── exer05-util.cs
│   │   ├── exer05a-product-matrix-vector.cs
│   │   ├── exer05b-product-matrix-matrix.cs
│   │   ├── exer06a-blocking-queue.cs
│   │   ├── exer06b01-blocking-queue.cs
│   │   ├── exer06b02-blocking-queue.cs
│   │   ├── exer07a-data-server.cs
│   │   ├── exer07b-data-server.cs
│   │   ├── exer07c-data-server.cs
│   │   ├── exer07d-data-server.cs
│   │   ├── exer08-exec-service-main.cs
│   │   ├── exer08-exec-service-v0a.cs
│   │   ├── exer08-exec-service-v0b.cs
│   │   ├── exer08-exec-service-v1a.cs
│   │   ├── exer08-exec-service-v1b.cs
│   │   ├── exer08-exec-service-v2a.cs
│   │   └── exer08-exec-service-v2b.cs
│   ├── multithreading.csproj
│   └── multithreading.sln
├── java/
│   ├── .gitignore
│   ├── README.md
│   └── src/
│       ├── demo00_intro/
│       │   └── App.java
│       ├── demo01_hello/
│       │   ├── AppA01.java
│       │   ├── AppA02.java
│       │   ├── AppB01.java
│       │   ├── AppB02.java
│       │   ├── AppB03.java
│       │   ├── AppC01.java
│       │   ├── AppC02.java
│       │   └── AppExtra.java
│       ├── demo02_join/
│       │   ├── AppA.java
│       │   └── AppB.java
│       ├── demo03_pass_arg/
│       │   ├── AppA.java
│       │   ├── AppB.java
│       │   └── AppC.java
│       ├── demo04_sleep/
│       │   └── App.java
│       ├── demo05_id/
│       │   └── App.java
│       ├── demo06_list_threads/
│       │   ├── AppA.java
│       │   ├── AppB01.java
│       │   └── AppB02.java
│       ├── demo07_terminate/
│       │   ├── AppA.java
│       │   └── AppB.java
│       ├── demo08_return_value/
│       │   ├── AppA.java
│       │   ├── AppB.java
│       │   └── AppC.java
│       ├── demo09_detach/
│       │   └── App.java
│       ├── demo10_yield/
│       │   └── App.java
│       ├── demo11_exec_service/
│       │   ├── AppA.java
│       │   ├── AppB01.java
│       │   ├── AppB02.java
│       │   ├── AppC01.java
│       │   ├── AppC02.java
│       │   ├── AppC03.java
│       │   ├── AppC04.java
│       │   ├── AppC05.java
│       │   ├── AppC06.java
│       │   └── AppExtra.java
│       ├── demo12_race_condition/
│       │   ├── AppA.java
│       │   ├── AppB01.java
│       │   ├── AppB02.java
│       │   ├── AppC01.java
│       │   └── AppC02.java
│       ├── demo13_mutex/
│       │   ├── AppA.java
│       │   └── AppB.java
│       ├── demo14_synchronized_block/
│       │   ├── AppA.java
│       │   ├── AppB01.java
│       │   ├── AppB02.java
│       │   └── AppC.java
│       ├── demo15_deadlock/
│       │   ├── AppA.java
│       │   └── AppB.java
│       ├── demo16_monitor/
│       │   └── App.java
│       ├── demo17_reentrant_lock/
│       │   ├── AppA01.java
│       │   ├── AppA02.java
│       │   ├── AppB01.java
│       │   └── AppB02.java
│       ├── demo18_barrier_latch/
│       │   ├── AppA01.java
│       │   ├── AppA02.java
│       │   ├── AppA03.java
│       │   ├── AppB01.java
│       │   └── AppB02.java
│       ├── demo19_read_write_lock/
│       │   └── App.java
│       ├── demo20_semaphore/
│       │   ├── AppA01.java
│       │   ├── AppA02.java
│       │   ├── AppA03.java
│       │   └── AppB.java
│       ├── demo21_condition_variable/
│       │   ├── AppA01.java
│       │   ├── AppA02.java
│       │   ├── AppA03.java
│       │   └── AppB.java
│       ├── demo22_blocking_queue/
│       │   ├── AppA.java
│       │   ├── AppB.java
│       │   └── AppExtra.java
│       ├── demo23_thread_local/
│       │   ├── AppA01.java
│       │   ├── AppA02.java
│       │   └── AppB.java
│       ├── demo24_volatile/
│       │   └── App.java
│       ├── demo25_atomic/
│       │   ├── AppA.java
│       │   └── AppB.java
│       ├── demoex/
│       │   └── async/
│       │       ├── AppA.java
│       │       ├── AppB01.java
│       │       ├── AppB02.java
│       │       ├── AppB03.java
│       │       ├── AppB04.java
│       │       ├── AppC01.java
│       │       └── AppC02.java
│       ├── exer01_max_div/
│       │   ├── AppA.java
│       │   ├── AppB.java
│       │   └── AppC.java
│       ├── exer02_producer_consumer/
│       │   ├── AppA01.java
│       │   ├── AppA02.java
│       │   ├── AppA03.java
│       │   ├── AppA04.java
│       │   ├── AppB01.java
│       │   ├── AppB02.java
│       │   ├── AppB03.java
│       │   ├── AppB04.java
│       │   └── AppC.java
│       ├── exer03_readers_writers/
│       │   ├── AppA.java
│       │   └── AppB.java
│       ├── exer04_dining_philosophers/
│       │   ├── AppA.java
│       │   └── AppB.java
│       ├── exer05_product_matrix/
│       │   ├── AppA.java
│       │   ├── AppB.java
│       │   └── MyUtil.java
│       ├── exer06_blocking_queue/
│       │   ├── AppA.java
│       │   ├── AppB01.java
│       │   └── AppB02.java
│       ├── exer07_data_server/
│       │   ├── AppA.java
│       │   ├── AppB.java
│       │   ├── AppC.java
│       │   └── AppD.java
│       └── exer08_exec_service/
│           ├── App.java
│           ├── MyExecServiceV0A.java
│           ├── MyExecServiceV0B.java
│           ├── MyExecServiceV1A.java
│           ├── MyExecServiceV1B.java
│           ├── MyExecServiceV2A.java
│           └── MyExecServiceV2B.java
├── js-nodejs/
│   ├── .gitignore
│   ├── demo00.js
│   ├── demo01a-hello.js
│   ├── demo01b-hello-worker.js
│   ├── demo01b-hello.js
│   ├── demo02-join.js
│   ├── demo03a-pass-arg.js
│   ├── demo03b-pass-arg.js
│   ├── demo04-sleep.js
│   ├── demo05-id.js
│   ├── demo06a-list-threads.js
│   ├── demo06b-list-threads.js
│   ├── demo07-terminate.js
│   ├── demo08a-return-value.js
│   ├── demo08b-return-value.js
│   ├── demo11a-exec-service.js
│   ├── demo11b-exec-service.js
│   ├── demo12-race-condition.js
│   ├── demo12b01-data-race-single.js
│   ├── demo12b02-data-race-multi.js
│   ├── demo12c-race-cond-data-race.js
│   ├── demo13-mutex.js
│   ├── demo13ex-mutex-problem.js
│   ├── demo13ex-mutex-solve.js
│   ├── demo15a-deadlock.js
│   ├── demo15b-deadlock.js
│   ├── demo15ex-deadlock.js
│   ├── demo25-atomic.js
│   ├── exer01a-max-div.js
│   ├── exer01c-max-div.js
│   ├── exerex-userhash-problem.js
│   ├── exerex-userhash-solve01.js
│   ├── exerex-userhash-solve02-faster.js
│   ├── exerex-userhash-solve03-faster.js
│   ├── exerex-userhash-util.js
│   ├── mylib.js
│   ├── mylib_mutex.js
│   └── package.json
├── notes-articles.md
├── notes-demos-exercises.md
├── old/
│   ├── cpppthread-reentrant-lock-a.cpp
│   ├── cpppthread-reentrant-lock-b.cpp
│   ├── cppstd-data-race.cpp
│   ├── cppstd-reentrant-lock-a.cpp
│   └── cppstd-reentrant-lock-b.cpp
├── python/
│   ├── .gitignore
│   ├── demo00.py
│   ├── demo01_hello.py
│   ├── demo01ex_name.py
│   ├── demo02a_join.py
│   ├── demo02b_join.py
│   ├── demo03a_pass_arg.py
│   ├── demo03b_pass_arg.py
│   ├── demo04_sleep.py
│   ├── demo05_id.py
│   ├── demo06_list_threads.py
│   ├── demo07_terminate.py
│   ├── demo08a_return_value.py
│   ├── demo08b_return_value.py
│   ├── demo09_detach.py
│   ├── demo10_yield.py
│   ├── demo11a_exec_service.py
│   ├── demo11b_exec_service.py
│   ├── demo11c01_exec_service.py
│   ├── demo11c02_exec_service.py
│   ├── demo12a_race_condition.py
│   ├── demo12b01_data_race_single.py
│   ├── demo12b02_data_race_multi.py
│   ├── demo12c01_race_cond_data_race.py
│   ├── demo12c02_race_cond_data_race.py
│   ├── demo13a_mutex.py
│   ├── demo14_synchronized_block.py
│   ├── demo15a_deadlock.py
│   ├── demo15b_deadlock.py
│   ├── demo16_monitor.py
│   ├── demo17a_reentrant_lock.py
│   ├── demo17b_reentrant_lock.py
│   ├── demo17c_reentrant_lock.py
│   ├── demo18a01_barrier.py
│   ├── demo18a02_barrier.py
│   ├── demo18a03_barrier.py
│   ├── demo18b01_latch.py
│   ├── demo18b02_latch.py
│   ├── demo19_read_write_lock.py
│   ├── demo20a01_semaphore.py
│   ├── demo20a02_semaphore.py
│   ├── demo20a03_semaphore_deadlock.py
│   ├── demo20b_semaphore.py
│   ├── demo21a01_condition_variable.py
│   ├── demo21a02_condition_variable.py
│   ├── demo21a03_condition_variable.py
│   ├── demo21b_condition_variable.py
│   ├── demo22a_blocking_queue.py
│   ├── demo22b_blocking_queue.py
│   ├── demo23a_thread_local.py
│   ├── demo23b_thread_local.py
│   ├── demo24_volatile.py
│   ├── demo25_atomic.py
│   ├── demoex_event.py
│   ├── demoex_timer.py
│   ├── exer01a_max_div.py
│   ├── exer01b_max_div.py
│   ├── exer01c_max_div.py
│   ├── exer02a01_producer_consumer.py
│   ├── exer02a02_producer_consumer.py
│   ├── exer02a03_producer_consumer.py
│   ├── exer02a04_producer_consumer.py
│   ├── exer02b01_producer_consumer.py
│   ├── exer02b02_producer_consumer.py
│   ├── exer02b03_producer_consumer.py
│   ├── exer02b04_producer_consumer.py
│   ├── exer02c_producer_consumer.py
│   ├── exer03a_readers_writers.py
│   ├── exer03b_readers_writers.py
│   ├── exer04_dining_philosophers.py
│   ├── exer05a_product_matrix_vector.py
│   ├── exer05b_product_matrix_vector.py
│   ├── exer06a_blocking_queue.py
│   ├── exer06b01_blocking_queue.py
│   ├── exer06b02_blocking_queue.py
│   ├── exer07a_data_server.py
│   ├── exer07b_data_server.py
│   ├── exer07c_data_server.py
│   ├── exer07d_data_server.py
│   ├── exer08_exec_service_itask.py
│   ├── exer08_exec_service_main.py
│   ├── exer08_exec_service_v0a.py
│   ├── exer08_exec_service_v0b.py
│   ├── exer08_exec_service_v1a.py
│   ├── exer08_exec_service_v1b.py
│   ├── exer08_exec_service_v2a.py
│   ├── exer08_exec_service_v2b.py
│   ├── mylib_latch.py
│   ├── mylib_rwlock.py
│   └── mylib_rwlock2.py
└── references.md
Download .txt
SYMBOL INDEX (2095 symbols across 617 files)

FILE: cpp/cpp-boost/demo00.cpp
  function doTask (line 13) | void doTask() {
  function main (line 20) | int main() {

FILE: cpp/cpp-boost/demo01a01-hello.cpp
  function doTask (line 13) | void doTask() {
  function main (line 19) | int main() {

FILE: cpp/cpp-boost/demo01a02-hello.cpp
  function doTask (line 13) | void doTask(char const* message, int number) {
  function main (line 19) | int main() {

FILE: cpp/cpp-boost/demo01b-hello-class01.cpp
  class Example (line 14) | class Example {
    method doTask (line 16) | void doTask(string message) {
  function main (line 23) | int main() {

FILE: cpp/cpp-boost/demo01b-hello-class02.cpp
  class Example (line 15) | class Example {
    method run (line 17) | void run() {
    method doTask (line 24) | void doTask(string message) {
  function main (line 31) | int main() {

FILE: cpp/cpp-boost/demo01b-hello-class03.cpp
  class Example (line 14) | class Example {
    method run (line 16) | void run() {
    method doTask (line 22) | static void doTask(string message) {
  function main (line 29) | int main() {

FILE: cpp/cpp-boost/demo01b-hello-functor.cpp
  class Example (line 14) | class Example {
  function main (line 23) | int main() {

FILE: cpp/cpp-boost/demo02-join.cpp
  function doHeavyTask (line 12) | void doHeavyTask() {
  function main (line 21) | int main() {

FILE: cpp/cpp-boost/demo03a-pass-arg.cpp
  type Point (line 15) | struct Point {
    method Point (line 19) | Point(int x, int y): x(x), y(y) { }
  function doTask (line 24) | void doTask(int a, double b, string c, char const* d, Point e) {
  function main (line 32) | int main() {

FILE: cpp/cpp-boost/demo03b-pass-arg.cpp
  function doTask (line 14) | void doTask(const string& msg) {
  function doTask (line 18) | void doTask(const string& msg) {
  function main (line 24) | int main() {

FILE: cpp/cpp-boost/demo03c-pass-arg.cpp
  function doTask (line 15) | void doTask(string& msg) {
  function main (line 21) | int main() {

FILE: cpp/cpp-boost/demo04a-sleep.cpp
  function doTask (line 15) | void doTask(string name) {
  function main (line 23) | int main() {

FILE: cpp/cpp-boost/demo04b-sleep.cpp
  function doTask (line 20) | void doTask(string name, sysclock::time_point tpWakeUp) {
  function main (line 27) | int main() {

FILE: cpp/cpp-boost/demo05-id.cpp
  function doTask (line 13) | void doTask() {
  function main (line 20) | int main() {

FILE: cpp/cpp-boost/demo06a-list-threads.cpp
  function doTask (line 13) | void doTask(int index) {
  function main (line 19) | int main() {

FILE: cpp/cpp-boost/demo06b-list-threads.cpp
  function doTask (line 19) | void doTask(int index) {
  function main (line 25) | int main() {

FILE: cpp/cpp-boost/demo06c-list-threads.cpp
  function doTask (line 14) | void doTask(int index) {
  function main (line 20) | int main() {

FILE: cpp/cpp-boost/demo07-terminate.cpp
  function doTask (line 17) | void doTask() {
  function main (line 26) | int main() {

FILE: cpp/cpp-boost/demo08-return-value.cpp
  function doubleValue (line 14) | void doubleValue(int arg, int* res) {
  function squareValue (line 20) | void squareValue(int arg, int& res) {
  function main (line 26) | int main() {

FILE: cpp/cpp-boost/demo09-detach.cpp
  function foo (line 13) | void foo() {
  function main (line 23) | int main() {

FILE: cpp/cpp-boost/demo10-yield.cpp
  function littleSleep (line 20) | void littleSleep(int us) {
  function main (line 32) | int main() {

FILE: cpp/cpp-boost/demo11a-exec-service.cpp
  function doTask (line 14) | void doTask() {
  class MyFunctor (line 20) | class MyFunctor {
  function main (line 29) | int main() {

FILE: cpp/cpp-boost/demo11b-exec-service.cpp
  function doTask (line 15) | void doTask(char id) {
  function main (line 23) | int main() {

FILE: cpp/cpp-boost/demo12a-race-condition.cpp
  function doTask (line 13) | void doTask(int index) {
  function main (line 20) | int main() {

FILE: cpp/cpp-boost/demo12b01-data-race-single.cpp
  function getResult (line 14) | int getResult(int N) {
  function main (line 29) | int main() {

FILE: cpp/cpp-boost/demo12b02-data-race-multi.cpp
  function markDiv2 (line 16) | void markDiv2(vector<bool> & a, int N) {
  function markDiv3 (line 23) | void markDiv3(vector<bool> & a, int N) {
  function main (line 30) | int main() {

FILE: cpp/cpp-boost/demo12c01-race-cond-data-race.cpp
  function increaseCounter (line 17) | void increaseCounter() {
  function main (line 27) | int main() {

FILE: cpp/cpp-boost/demo12c02-race-cond-data-race.cpp
  function doTaskA (line 21) | void doTaskA(sysclock::time_point timePointWakeUp) {
  function doTaskB (line 32) | void doTaskB(sysclock::time_point timePointWakeUp) {
  function main (line 43) | int main() {

FILE: cpp/cpp-boost/demo13a-mutex.cpp
  function doTask (line 18) | void doTask() {
  function main (line 31) | int main() {

FILE: cpp/cpp-boost/demo13b01-mutex.cpp
  function doTask (line 18) | void doTask() {
  function main (line 32) | int main() {

FILE: cpp/cpp-boost/demo13b02-mutex.cpp
  function doTask (line 28) | void doTask() {
  function main (line 39) | int main() {

FILE: cpp/cpp-boost/demo13c-mutex-trylock.cpp
  function doTask (line 19) | void doTask() {
  function main (line 34) | int main() {

FILE: cpp/cpp-boost/demo14-synchronized-block.cpp
  function doTask (line 30) | void doTask() {
  function main (line 44) | int main() {

FILE: cpp/cpp-boost/demo15a-deadlock.cpp
  function doTask (line 18) | void doTask(std::string name) {
  function main (line 28) | int main() {

FILE: cpp/cpp-boost/demo15b-deadlock.cpp
  function foo (line 19) | void foo() {
  function bar (line 34) | void bar() {
  function main (line 49) | int main() {

FILE: cpp/cpp-boost/demo16-monitor.cpp
  class Monitor (line 14) | class Monitor {
    method init (line 24) | void init(int* pCounter) {
    method increaseCounter (line 29) | void increaseCounter() {
  function doTask (line 38) | void doTask(Monitor* monitor) {
  function main (line 47) | int main() {

FILE: cpp/cpp-boost/demo17a-reentrant-lock.cpp
  function doTask (line 17) | void doTask() {
  function main (line 30) | int main() {

FILE: cpp/cpp-boost/demo17b-reentrant-lock.cpp
  function doTask (line 17) | void doTask() {
  function doTaskUsingSyncBlock (line 30) | void doTaskUsingSyncBlock() {
  function main (line 44) | int main() {

FILE: cpp/cpp-boost/demo17c-reentrant-lock.cpp
  function doTask (line 18) | void doTask(char name) {
  function doTaskUsingSyncBlock (line 33) | void doTaskUsingSyncBlock(char name) {
  function main (line 51) | int main() {

FILE: cpp/cpp-boost/demo18a01-barrier.cpp
  function processRequest (line 22) | void processRequest(string userName, int waitTime) {
  function main (line 36) | int main() {

FILE: cpp/cpp-boost/demo18a02-barrier.cpp
  function processRequest (line 22) | void processRequest(string userName, int waitTime) {
  function main (line 36) | int main() {

FILE: cpp/cpp-boost/demo18a03-barrier.cpp
  function processRequest (line 23) | void processRequest(string userName, int waitTime) {
  function main (line 37) | int main() {

FILE: cpp/cpp-boost/demo18b01-latch.cpp
  function processRequest (line 23) | void processRequest(string userName, int waitTime) {
  function main (line 37) | int main() {

FILE: cpp/cpp-boost/demo18b02-latch.cpp
  function doTask (line 26) | void doTask(string message, int waitTime) {
  function main (line 38) | int main() {

FILE: cpp/cpp-boost/demo19a-read-write-lock.cpp
  function readFunc (line 20) | void readFunc(int waitTime) {
  function writeFunc (line 32) | void writeFunc(int waitTime) {
  function main (line 45) | int main() {

FILE: cpp/cpp-boost/demo19b-read-write-lock.cpp
  function readFunc (line 20) | void readFunc(int waitTime) {
  function writeFunc (line 32) | void writeFunc(int waitTime) {
  function main (line 46) | int main() {

FILE: cpp/cpp-boost/demo20a01-semaphore.cpp
  function makeOneSheet (line 22) | void makeOneSheet() {
  function combineOnePackage (line 32) | void combineOnePackage() {
  function main (line 42) | int main() {

FILE: cpp/cpp-boost/demo20a02-semaphore.cpp
  function makeOneSheet (line 23) | void makeOneSheet() {
  function combineOnePackage (line 33) | void combineOnePackage() {
  function main (line 48) | int main() {

FILE: cpp/cpp-boost/demo20a03-semaphore-deadlock.cpp
  function makeOneSheet (line 23) | void makeOneSheet() {
  function combineOnePackage (line 33) | void combineOnePackage() {
  function main (line 48) | int main() {

FILE: cpp/cpp-boost/demo20b-semaphore.cpp
  function makeTire (line 23) | void makeTire() {
  function makeChassis (line 36) | void makeChassis() {
  function main (line 55) | int main() {

FILE: cpp/cpp-boost/demo21a01-condition-variable.cpp
  function foo (line 18) | void foo() {
  function bar (line 29) | void bar() {
  function main (line 36) | int main() {

FILE: cpp/cpp-boost/demo21a02-condition-variable.cpp
  function foo (line 20) | void foo() {
  function bar (line 31) | void bar() {
  function main (line 40) | int main() {

FILE: cpp/cpp-boost/demo21a03-condition-variable.cpp
  function foo (line 20) | void foo() {
  function bar (line 31) | void bar() {
  function main (line 39) | int main() {

FILE: cpp/cpp-boost/demo21b-condition-variable.cpp
  function foo (line 25) | void foo() {
  function egg (line 46) | void egg() {
  function main (line 68) | int main() {

FILE: cpp/cpp-boost/demo22a-blocking-queue.cpp
  function producer (line 20) | void producer(BlockingQueue<string>* blkQueue) {
  function consumer (line 33) | void consumer(BlockingQueue<string>* blkQueue) {
  function main (line 45) | int main() {

FILE: cpp/cpp-boost/demo22b-blocking-queue.cpp
  function producer (line 20) | void producer(BlockingQueue<string>* blkQueue) {
  function consumer (line 34) | void consumer(BlockingQueue<string>* blkQueue) {
  function main (line 47) | int main() {

FILE: cpp/cpp-boost/demo23a-thread-local.cpp
  function printLocalValue (line 20) | void printLocalValue() {
  function doTaskApple (line 26) | void doTaskApple() {
  function doTaskBanana (line 34) | void doTaskBanana() {
  function main (line 42) | int main() {

FILE: cpp/cpp-boost/demo23b-thread-local.cpp
  function doTask (line 18) | void doTask(int t) {
  function main (line 30) | int main() {

FILE: cpp/cpp-boost/demo24-volatile.cpp
  function doTask (line 17) | void doTask() {
  function main (line 26) | int main() {

FILE: cpp/cpp-boost/demo25a-atomic.cpp
  function doTask (line 17) | void doTask() {
  function main (line 24) | int main() {

FILE: cpp/cpp-boost/demo25b-atomic.cpp
  function doTask (line 18) | void doTask() {
  function main (line 25) | int main() {

FILE: cpp/cpp-boost/demoex-async-future.cpp
  function doTaskA (line 13) | int doTaskA() {
  function doTaskB (line 17) | int doTaskB() {
  function doTaskC (line 21) | void doTaskC(boost::promise<int> & prom) {
  function main (line 27) | int main() {

FILE: cpp/cpp-boost/exer01a-max-div.cpp
  function main (line 18) | int main() {

FILE: cpp/cpp-boost/exer01b-max-div.cpp
  type WorkerArg (line 21) | struct WorkerArg {
    method WorkerArg (line 25) | WorkerArg(int iStart = 0, int iEnd = 0): iStart(iStart), iEnd(iEnd)
  type WorkerResult (line 32) | struct WorkerResult {
    method WorkerResult (line 36) | WorkerResult(int value = 0, int numDiv = 0): value(value), numDiv(numDiv)
  function workerFunc (line 43) | void workerFunc(WorkerArg* arg, WorkerResult* res) {
  function prepare (line 65) | void prepare(
  function main (line 91) | int main() {

FILE: cpp/cpp-boost/exer01c-max-div.cpp
  type WorkerArg (line 21) | struct WorkerArg {
    method WorkerArg (line 25) | WorkerArg(int iStart = 0, int iEnd = 0): iStart(iStart), iEnd(iEnd)
  class FinalResult (line 32) | class FinalResult {
    method FinalResult (line 42) | FinalResult(): value(0), numDiv(0) { }
    method update (line 45) | void update(int value, int numDiv) {
  function workerFunc (line 58) | void workerFunc(WorkerArg* arg, FinalResult* res) {
  function prepare (line 80) | void prepare(
  function main (line 104) | int main() {

FILE: cpp/cpp-boost/exer02a01-producer-consumer.cpp
  function producer (line 18) | void producer(BlockingQueue<int>* blkq) {
  function consumer (line 29) | void consumer(BlockingQueue<int>* blkq) {
  function main (line 40) | int main() {

FILE: cpp/cpp-boost/exer02a02-producer-consumer.cpp
  function producer (line 18) | void producer(BlockingQueue<int>* blkq) {
  function consumer (line 29) | void consumer(BlockingQueue<int>* blkq) {
  function main (line 40) | int main() {

FILE: cpp/cpp-boost/exer02a03-producer-consumer.cpp
  function producer (line 19) | void producer(BlockingQueue<int>* blkq) {
  function consumer (line 30) | void consumer(string name, BlockingQueue<int>* blkq) {
  function main (line 41) | int main() {

FILE: cpp/cpp-boost/exer02a04-producer-consumer.cpp
  function producer (line 18) | void producer(BlockingQueue<int>* blkq, int startValue) {
  function consumer (line 28) | void consumer(BlockingQueue<int>* blkq) {
  function main (line 40) | int main() {

FILE: cpp/cpp-boost/exer02b01-producer-consumer.cpp
  function producer (line 18) | void producer(
  function consumer (line 37) | void consumer(
  function main (line 58) | int main() {

FILE: cpp/cpp-boost/exer02b02-producer-consumer.cpp
  function producer (line 18) | void producer(
  function consumer (line 38) | void consumer(
  function main (line 59) | int main() {

FILE: cpp/cpp-boost/exer02b03-producer-consumer.cpp
  function producer (line 18) | void producer(
  function consumer (line 35) | void consumer(
  function main (line 57) | int main() {

FILE: cpp/cpp-boost/exer02b04-producer-consumer.cpp
  function producer (line 18) | void producer(
  function consumer (line 35) | void consumer(
  function main (line 57) | int main() {

FILE: cpp/cpp-boost/exer02c-producer-consumer.cpp
  class Monitor (line 18) | class Monitor {
    method Monitor (line 29) | Monitor() : q(0), maxQueueSize(0) { }
    method Monitor (line 33) | Monitor(const Monitor& other) { }
    method init (line 38) | void init(int maxQueueSize, std::queue<T>* q) {
    method add (line 44) | void add(const T& item) {
    method T (line 61) | T remove() {
  function producer (line 84) | void producer(Monitor<T>* monitor, int startValue) {
  function consumer (line 95) | void consumer(Monitor<T>* monitor) {
  function main (line 107) | int main() {

FILE: cpp/cpp-boost/exer03a-readers-writers.cpp
  type GlobalData (line 15) | struct GlobalData {
  function doTaskWriter (line 25) | void doTaskWriter(GlobalData* g, int delayTime) {
  function doTaskReader (line 38) | void doTaskReader(GlobalData* g, int delayTime) {
  function main (line 68) | int main() {

FILE: cpp/cpp-boost/exer03b-readers-writers.cpp
  type GlobalData (line 15) | struct GlobalData {
  function doTaskWriter (line 27) | void doTaskWriter(GlobalData* g, int delayTime) {
  function doTaskReader (line 44) | void doTaskReader(GlobalData* g, int delayTime) {
  function main (line 80) | int main() {

FILE: cpp/cpp-boost/exer04-dining-philosophers.cpp
  function doTaskPhilosopher (line 13) | void doTaskPhilosopher(boost::mutex chopstick[], int numPhilo, int idPhi...
  function doTaskPhilosopherUsingSyncBlock (line 30) | void doTaskPhilosopherUsingSyncBlock(boost::mutex chopstick[], int numPh...
  function main (line 45) | int main() {

FILE: cpp/cpp-boost/exer05-util.hpp
  function getScalarProduct (line 6) | void getScalarProduct(double const* u, double const* v, int sizeVector, ...

FILE: cpp/cpp-boost/exer05a-product-matrix-vector.cpp
  function getProduct (line 21) | void getProduct(const matrix& mat, const vectord& vec, vectord& result) {
  function main (line 43) | int main() {

FILE: cpp/cpp-boost/exer05b-product-matrix-matrix.cpp
  function getTransposeMatrix (line 21) | void getTransposeMatrix(const matrix& input, matrix& output) {
  function displayMatrix (line 35) | void displayMatrix(const matrix& mat) {
  function getProduct (line 49) | void getProduct(const matrix& matA, const matrix& matB, matrix& result) {
  function main (line 79) | int main() {

FILE: cpp/cpp-boost/exer06a-blocking-queue.cpp
  class SynchronousQueue (line 17) | class SynchronousQueue {
    method SynchronousQueue (line 26) | SynchronousQueue() : semPut(1), semTake(0) { }
    method put (line 29) | void put(const T& value) {
    method T (line 36) | T take() {
  function producer (line 47) | void producer(SynchronousQueue<std::string>* syncQueue) {
  function consumer (line 60) | void consumer(SynchronousQueue<std::string>* syncQueue) {
  function main (line 72) | int main() {

FILE: cpp/cpp-boost/exer06b01-blocking-queue.cpp
  class BlockingQueue (line 20) | class BlockingQueue {
    method BlockingQueue (line 33) | BlockingQueue(int capacity) : capacity(capacity), semRemain(capacity),...
    method put (line 39) | void put(const T& value) {
    method T (line 51) | T take() {
  function producer (line 69) | void producer(BlockingQueue<std::string>* blkQueue) {
  function consumer (line 82) | void consumer(BlockingQueue<std::string>* blkQueue) {
  function main (line 97) | int main() {

FILE: cpp/cpp-boost/exer06b02-blocking-queue.cpp
  class BlockingQueue (line 19) | class BlockingQueue {
    method BlockingQueue (line 31) | BlockingQueue(int capacity) {
    method put (line 39) | void put(const T& value) {
    method T (line 55) | T take() {
  function producer (line 78) | void producer(BlockingQueue<std::string>* blkQueue) {
  function consumer (line 91) | void consumer(BlockingQueue<std::string>* blkQueue) {
  function main (line 106) | int main() {

FILE: cpp/cpp-boost/exer07a-data-server.cpp
  type Counter (line 22) | struct Counter {
    method Counter (line 26) | Counter(int value) : value(value) { }
  function checkAuthUser (line 31) | void checkAuthUser() {
  function processFiles (line 40) | void processFiles(const vector<string>& lstFileName, Counter& counter) {
  function processRequest (line 63) | void processRequest() {
  function main (line 90) | int main() {

FILE: cpp/cpp-boost/exer07b-data-server.cpp
  function checkAuthUser (line 23) | void checkAuthUser() {
  function processFiles (line 32) | void processFiles(const vector<string>& lstFileName, mylib::Semaphore& s...
  function processRequest (line 51) | void processRequest() {
  function main (line 75) | int main() {

FILE: cpp/cpp-boost/exer07c-data-server.cpp
  function checkAuthUser (line 23) | void checkAuthUser() {
  function processFiles (line 32) | void processFiles(const vector<string>& lstFileName, boost::latch& rdLat...
  function processRequest (line 51) | void processRequest() {
  function main (line 73) | int main() {

FILE: cpp/cpp-boost/exer07d-data-server.cpp
  function checkAuthUser (line 23) | void checkAuthUser() {
  function processFiles (line 32) | void processFiles(const vector<string>& lstFileName, mylib::BlockingQueu...
  function processRequest (line 51) | void processRequest() {
  function main (line 75) | int main() {

FILE: cpp/cpp-boost/exer08-exec-service-itask.hpp
  class ITask (line 7) | class ITask {

FILE: cpp/cpp-boost/exer08-exec-service-main.cpp
  class MyTask (line 19) | class MyTask : public ITask {
    method run (line 24) | void run() {
  function main (line 33) | int main() {

FILE: cpp/cpp-boost/exer08-exec-service-v0a.hpp
  class MyExecServiceV0A (line 24) | class MyExecServiceV0A {
    method MyExecServiceV0A (line 33) | MyExecServiceV0A(int numThreads) {
    method MyExecServiceV0A (line 39) | MyExecServiceV0A(const MyExecServiceV0A& other) : numThreads(0) { }
    method MyExecServiceV0A (line 43) | MyExecServiceV0A(const MyExecServiceV0A&& other) : numThreads(0) { }
    method init (line 49) | void init(int numThreads) {
    method submit (line 59) | void submit(ITask* task) {
    method waitTaskDone (line 64) | void waitTaskDone() {
    method shutdown (line 71) | void shutdown() {
    method threadWorkerFunc (line 81) | static void threadWorkerFunc(MyExecServiceV0A* thisPtr) {

FILE: cpp/cpp-boost/exer08-exec-service-v0b.hpp
  class MyExecServiceV0B (line 24) | class MyExecServiceV0B {
    method run (line 36) | void run() { }
    method MyExecServiceV0B (line 42) | MyExecServiceV0B(int numThreads) {
    method MyExecServiceV0B (line 48) | MyExecServiceV0B(const MyExecServiceV0B& other) : numThreads(0) { }
    method MyExecServiceV0B (line 52) | MyExecServiceV0B(const MyExecServiceV0B&& other) : numThreads(0) { }
    method init (line 58) | void init(int numThreads) {
    method submit (line 70) | void submit(ITask* task) {
    method waitTaskDone (line 75) | void waitTaskDone() {
    method shutdown (line 85) | void shutdown() {
    method threadWorkerFunc (line 100) | static void threadWorkerFunc(MyExecServiceV0B* thisPtr) {

FILE: cpp/cpp-boost/exer08-exec-service-v1a.hpp
  class MyExecServiceV1A (line 23) | class MyExecServiceV1A {
    method MyExecServiceV1A (line 43) | MyExecServiceV1A(int numThreads) {
    method MyExecServiceV1A (line 49) | MyExecServiceV1A(const MyExecServiceV1A& other) : numThreads(0) { }
    method MyExecServiceV1A (line 53) | MyExecServiceV1A(const MyExecServiceV1A&& other) : numThreads(0) { }
    method init (line 59) | void init(int numThreads) {
    method submit (line 73) | void submit(ITask* task) {
    method waitTaskDone (line 83) | void waitTaskDone() {
    method shutdown (line 105) | void shutdown() {
    method threadWorkerFunc (line 121) | static void threadWorkerFunc(MyExecServiceV1A* thisPtr) {

FILE: cpp/cpp-boost/exer08-exec-service-v1b.hpp
  class MyExecServiceV1B (line 22) | class MyExecServiceV1B {
    method MyExecServiceV1B (line 44) | MyExecServiceV1B(int numThreads) {
    method MyExecServiceV1B (line 50) | MyExecServiceV1B(const MyExecServiceV1B& other) : numThreads(0) { }
    method MyExecServiceV1B (line 54) | MyExecServiceV1B(const MyExecServiceV1B&& other) : numThreads(0) { }
    method init (line 60) | void init(int numThreads) {
    method submit (line 74) | void submit(ITask* task) {
    method waitTaskDone (line 84) | void waitTaskDone() {
    method shutdown (line 101) | void shutdown() {
    method threadWorkerFunc (line 117) | static void threadWorkerFunc(MyExecServiceV1B* thisPtr) {

FILE: cpp/cpp-boost/exer08-exec-service-v2a.hpp
  class MyExecServiceV2A (line 24) | class MyExecServiceV2A {
    method MyExecServiceV2A (line 46) | MyExecServiceV2A(int numThreads) : counterTaskRunning(0) {
    method MyExecServiceV2A (line 52) | MyExecServiceV2A(const MyExecServiceV2A& other) : numThreads(0), count...
    method MyExecServiceV2A (line 56) | MyExecServiceV2A(const MyExecServiceV2A&& other) : numThreads(0), coun...
    method init (line 62) | void init(int numThreads) {
    method submit (line 75) | void submit(ITask* task) {
    method waitTaskDone (line 85) | void waitTaskDone() {
    method shutdown (line 101) | void shutdown() {
    method threadWorkerFunc (line 117) | static void threadWorkerFunc(MyExecServiceV2A* thisPtr) {

FILE: cpp/cpp-boost/exer08-exec-service-v2b.hpp
  class MyExecServiceV2B (line 23) | class MyExecServiceV2B {
    method MyExecServiceV2B (line 45) | MyExecServiceV2B(int numThreads) {
    method MyExecServiceV2B (line 51) | MyExecServiceV2B(const MyExecServiceV2B& other) : numThreads(0) { }
    method MyExecServiceV2B (line 55) | MyExecServiceV2B(const MyExecServiceV2B&& other) : numThreads(0) { }
    method init (line 61) | void init(int numThreads) {
    method submit (line 74) | void submit(ITask* task) {
    method waitTaskDone (line 84) | void waitTaskDone() {
    method shutdown (line 101) | void shutdown() {
    method threadWorkerFunc (line 117) | static void threadWorkerFunc(MyExecServiceV2B* thisPtr) {

FILE: cpp/cpp-boost/mylib-blockingqueue.hpp
  type mylib (line 30) | namespace mylib
    class BlockingQueue (line 36) | class BlockingQueue {
      method BlockingQueue (line 52) | BlockingQueue() : capacity(std::numeric_limits<size_t>::max()) {
      method BlockingQueue (line 56) | BlockingQueue(size_t capacity) : capacity(capacity) {
      method BlockingQueue (line 61) | BlockingQueue(const BlockingQueue& other) { }
      method BlockingQueue (line 65) | BlockingQueue(const BlockingQueue&& other) { }
      method empty (line 71) | bool empty() const {
      method size (line 76) | size_t size() const {
      method put (line 82) | void put(const T& value) {
      method T (line 95) | T take() {
      method add (line 111) | void add(const T& value) {
      method peek (line 119) | bool peek(T& result) const {
      method clear (line 131) | void clear() {

FILE: cpp/cpp-boost/mylib-random.hpp
  type mylib (line 28) | namespace mylib {
    class RandInt (line 32) | class RandInt {
      method RandInt (line 41) | RandInt() {
      method RandInt (line 46) | RandInt(int minValue, int maxValueInclusive) {
      method init (line 51) | void init(int minValue, int maxValueInclusive) {
      method next (line 57) | int next() {
      method RandInt (line 63) | RandInt(const RandInt& other) { }
      method get (line 72) | static int get(int maxExclusive) {

FILE: cpp/cpp-boost/mylib-semaphore.hpp
  type mylib (line 30) | namespace mylib
    class Semaphore (line 35) | class Semaphore {
      method Semaphore (line 51) | Semaphore(int initialValue) {
      method Semaphore (line 57) | Semaphore(const Semaphore& other) { }
      method Semaphore (line 61) | Semaphore(const Semaphore&& other) { }
      method acquire (line 67) | void acquire() {
      method release (line 80) | void release() {
      method getValue (line 93) | int getValue() const {

FILE: cpp/cpp-boost/mylib-time.hpp
  type mylib (line 26) | namespace mylib
    class HiResClock (line 36) | class HiResClock {
      method now (line 43) | static inline stdhrc::time_point now()
      method duType (line 50) | static inline
      method duType (line 62) | static inline
    function getTimePoint (line 83) | class clock::time_point getTimePoint(
    function getTimePointFutureFloor (line 102) | chro::time_point<clock>

FILE: cpp/cpp-pthread/demo00.cpp
  function main (line 23) | int main() {

FILE: cpp/cpp-pthread/demo01-hello.cpp
  function main (line 21) | int main() {

FILE: cpp/cpp-pthread/demo02-join.cpp
  function main (line 24) | int main() {

FILE: cpp/cpp-pthread/demo03a01-pass-arg.cpp
  function main (line 28) | int main() {

FILE: cpp/cpp-pthread/demo03a02-pass-arg.cpp
  function main (line 24) | int main() {

FILE: cpp/cpp-pthread/demo03b01-pass-arg.cpp
  type ThreadArg (line 14) | struct ThreadArg {
  function main (line 35) | int main() {

FILE: cpp/cpp-pthread/demo03b02-pass-arg.cpp
  function main (line 28) | int main() {

FILE: cpp/cpp-pthread/demo04-sleep.cpp
  function main (line 26) | int main() {

FILE: cpp/cpp-pthread/demo05-id.cpp
  function main (line 23) | int main() {

FILE: cpp/cpp-pthread/demo06a-list-threads.cpp
  function main (line 23) | int main() {

FILE: cpp/cpp-pthread/demo06b-list-threads.cpp
  function main (line 24) | int main() {

FILE: cpp/cpp-pthread/demo07a-terminate.cpp
  function main (line 30) | int main() {

FILE: cpp/cpp-pthread/demo07b-terminate.cpp
  function main (line 26) | int main() {

FILE: cpp/cpp-pthread/demo08a-return-value.cpp
  type ThreadArg (line 13) | struct ThreadArg {
  function main (line 31) | int main() {

FILE: cpp/cpp-pthread/demo08b-return-value.cpp
  function main (line 25) | int main() {

FILE: cpp/cpp-pthread/demo09a-detach.cpp
  function main (line 26) | int main() {

FILE: cpp/cpp-pthread/demo09b-detach.cpp
  function main (line 32) | int main() {

FILE: cpp/cpp-pthread/demo10-yield.cpp
  function littleSleep (line 20) | void littleSleep(int us) {
  function main (line 35) | int main() {

FILE: cpp/cpp-pthread/demo11a-exec-service.cpp
  function doTask (line 15) | void doTask() {
  class MyFunctor (line 21) | class MyFunctor {
  function main (line 30) | int main() {

FILE: cpp/cpp-pthread/demo11b-exec-service.cpp
  function main (line 16) | int main() {

FILE: cpp/cpp-pthread/demo12a-race-condition.cpp
  function main (line 26) | int main() {

FILE: cpp/cpp-pthread/demo12b01-data-race-single.cpp
  function getResult (line 18) | int getResult() {
  function main (line 39) | int main() {

FILE: cpp/cpp-pthread/demo12b02-data-race-multi.cpp
  function main (line 39) | int main() {

FILE: cpp/cpp-pthread/demo12bex-data-race-fork.cpp
  function main (line 13) | int main() {

FILE: cpp/cpp-pthread/demo12c01-race-cond-data-race.cpp
  function main (line 30) | int main() {

FILE: cpp/cpp-pthread/demo12c02-race-cond-data-race.cpp
  function main (line 45) | int main() {

FILE: cpp/cpp-pthread/demo13a-mutex.cpp
  function main (line 34) | int main() {

FILE: cpp/cpp-pthread/demo13b-mutex-trylock.cpp
  function main (line 71) | int main() {

FILE: cpp/cpp-pthread/demo14-synchronized-block.cpp
  class LockGuard (line 24) | class LockGuard {
    method LockGuard (line 30) | LockGuard(const LockGuard&) = delete;
    method LockGuard (line 31) | LockGuard(const LockGuard&&) = delete;
    method LockGuard (line 36) | LockGuard(pthread_mutex_t* mut) {
  function main (line 71) | int main() {

FILE: cpp/cpp-pthread/demo15a-deadlock.cpp
  function main (line 32) | int main() {

FILE: cpp/cpp-pthread/demo15b-deadlock.cpp
  function main (line 55) | int main() {

FILE: cpp/cpp-pthread/demo16-monitor.cpp
  class Monitor (line 14) | class Monitor {
    method init (line 24) | void init(int* pCounter) {
    method increaseCounter (line 31) | void increaseCounter() {
    method destroy (line 39) | void destroy() {
  function main (line 60) | int main() {

FILE: cpp/cpp-pthread/demo17a-reentrant-lock.cpp
  function main (line 33) | int main() {

FILE: cpp/cpp-pthread/demo17b-reentrant-lock.cpp
  function main (line 33) | int main() {

FILE: cpp/cpp-pthread/demo17c-reentrant-lock.cpp
  function main (line 37) | int main() {

FILE: cpp/cpp-pthread/demo18a01-barrier.cpp
  function main (line 41) | int main() {

FILE: cpp/cpp-pthread/demo18a02-barrier.cpp
  function main (line 41) | int main() {

FILE: cpp/cpp-pthread/demo18a03-barrier.cpp
  function main (line 42) | int main() {

FILE: cpp/cpp-pthread/demo18b01-latch.cpp
  function main (line 44) | int main() {

FILE: cpp/cpp-pthread/demo18b02-latch.cpp
  function main (line 46) | int main() {

FILE: cpp/cpp-pthread/demo19-read-write-lock.cpp
  function main (line 72) | int main() {

FILE: cpp/cpp-pthread/demo20a01-semaphore.cpp
  function main (line 45) | int main() {

FILE: cpp/cpp-pthread/demo20a02-semaphore.cpp
  function main (line 51) | int main() {

FILE: cpp/cpp-pthread/demo20a03-semaphore-deadlock.cpp
  function main (line 51) | int main() {

FILE: cpp/cpp-pthread/demo20b-semaphore.cpp
  function main (line 60) | int main() {

FILE: cpp/cpp-pthread/demo21a01-condition-variable.cpp
  function main (line 44) | int main() {

FILE: cpp/cpp-pthread/demo21a02-condition-variable.cpp
  function main (line 48) | int main() {

FILE: cpp/cpp-pthread/demo21a03-condition-variable.cpp
  function main (line 47) | int main() {

FILE: cpp/cpp-pthread/demo21b-condition-variable.cpp
  function main (line 82) | int main() {

FILE: cpp/cpp-pthread/demo22a-blocking-queue.cpp
  function main (line 54) | int main() {

FILE: cpp/cpp-pthread/demo22b-blocking-queue.cpp
  function main (line 57) | int main() {

FILE: cpp/cpp-pthread/demo23a-thread-local.cpp
  function main (line 27) | int main() {

FILE: cpp/cpp-pthread/demo23b-thread-local.cpp
  function main (line 37) | int main() {

FILE: cpp/cpp-pthread/demo24-volatile.cpp
  function main (line 29) | int main() {

FILE: cpp/cpp-pthread/demo25a-atomic.c
  function main (line 28) | int main() {

FILE: cpp/cpp-pthread/demo25b-atomic.c
  function main (line 29) | int main() {

FILE: cpp/cpp-pthread/demoex-attribute.cpp
  function main (line 22) | int main() {

FILE: cpp/cpp-pthread/demoex-oop.cpp
  class Task (line 7) | class Task {
    method Task (line 15) | Task(const Task& other) = delete;
    method Task (line 16) | Task(const Task&& other) = delete;
    method Task (line 21) | Task(int index = -1): index(index) {
    method start (line 26) | int start() {
    method join (line 32) | int join() {
  function main (line 51) | int main() {

FILE: cpp/cpp-pthread/demoex-signal.cpp
  function signalHandler (line 9) | void signalHandler(int sig) {
  function main (line 26) | int main() {

FILE: cpp/cpp-pthread/exer01a-max-div.cpp
  function main (line 12) | int main() {

FILE: cpp/cpp-pthread/exer01b-max-div.cpp
  type WorkerResult (line 15) | struct WorkerResult {
    method WorkerResult (line 19) | WorkerResult(int value = 0, int numDiv = 0): value(value), numDiv(numDiv)
  type WorkerArg (line 26) | struct WorkerArg {
    method WorkerArg (line 31) | WorkerArg(int iStart = 0, int iEnd = 0, WorkerResult* res = nullptr):
  function prepare (line 67) | void prepare(
  function main (line 95) | int main() {

FILE: cpp/cpp-pthread/exer01c-max-div.cpp
  class FinalResult (line 15) | class FinalResult {
    method update (line 25) | void update(int value, int numDiv) {
    method init (line 36) | void init() {
    method destroy (line 41) | void destroy() {
  type WorkerArg (line 48) | struct WorkerArg {
    method WorkerArg (line 53) | WorkerArg(int iStart = 0, int iEnd = 0, FinalResult* res = nullptr):
  function prepare (line 89) | void prepare(
  function main (line 116) | int main() {

FILE: cpp/cpp-pthread/exer02a01-producer-consumer.cpp
  function main (line 48) | int main() {

FILE: cpp/cpp-pthread/exer02a02-producer-consumer.cpp
  function main (line 48) | int main() {

FILE: cpp/cpp-pthread/exer02a03-producer-consumer.cpp
  type ConsumerArg (line 19) | struct ConsumerArg {
  function main (line 58) | int main() {

FILE: cpp/cpp-pthread/exer02a04-producer-consumer.cpp
  type ProducerArg (line 18) | struct ProducerArg {
  function main (line 55) | int main() {

FILE: cpp/cpp-pthread/exer02b01-producer-consumer.cpp
  type GlobalSemaphore (line 18) | struct GlobalSemaphore {
    method init (line 22) | void init(int semFillValue, int semEmptyValue) {
    method destroy (line 27) | void destroy() {
    method waitFill (line 32) | void waitFill() {
    method waitEmpty (line 36) | void waitEmpty() {
    method postFill (line 40) | void postFill() {
    method postEmpty (line 44) | void postEmpty() {
  type GlobalArg (line 51) | struct GlobalArg {
  function main (line 104) | int main() {

FILE: cpp/cpp-pthread/exer02b02-producer-consumer.cpp
  type GlobalSemaphore (line 18) | struct GlobalSemaphore {
    method init (line 22) | void init(int semFillValue, int semEmptyValue) {
    method destroy (line 27) | void destroy() {
    method waitFill (line 32) | void waitFill() {
    method waitEmpty (line 36) | void waitEmpty() {
    method postFill (line 40) | void postFill() {
    method postEmpty (line 44) | void postEmpty() {
  type GlobalArg (line 51) | struct GlobalArg {
  function main (line 105) | int main() {

FILE: cpp/cpp-pthread/exer02b03-producer-consumer.cpp
  type GlobalSemaphore (line 18) | struct GlobalSemaphore {
    method init (line 22) | void init(int semFillValue, int semEmptyValue) {
    method destroy (line 27) | void destroy() {
    method waitFill (line 32) | void waitFill() {
    method waitEmpty (line 36) | void waitEmpty() {
    method postFill (line 40) | void postFill() {
    method postEmpty (line 44) | void postEmpty() {
  type GlobalArg (line 51) | struct GlobalArg {
  function main (line 103) | int main() {

FILE: cpp/cpp-pthread/exer02b04-producer-consumer.cpp
  type GlobalSemaphore (line 18) | struct GlobalSemaphore {
    method init (line 22) | void init(int semFillValue, int semEmptyValue) {
    method destroy (line 27) | void destroy() {
    method waitFill (line 32) | void waitFill() {
    method waitEmpty (line 36) | void waitEmpty() {
    method postFill (line 40) | void postFill() {
    method postEmpty (line 44) | void postEmpty() {
  type GlobalArg (line 51) | struct GlobalArg {
  function main (line 103) | int main() {

FILE: cpp/cpp-pthread/exer02c-producer-consumer.cpp
  class Monitor (line 19) | class Monitor {
    method Monitor (line 30) | Monitor() = default;
    method Monitor (line 31) | Monitor(const Monitor &other) = delete;
    method Monitor (line 32) | Monitor(const Monitor &&other) = delete;
    method init (line 37) | void init(int maxQueueSize, std::queue<T>* q) {
    method destroy (line 48) | void destroy() {
    method add (line 57) | void add(const T& item) {
    method T (line 74) | T remove() {
  type ProducerArg (line 97) | struct ProducerArg {
  function main (line 139) | int main() {

FILE: cpp/cpp-pthread/exer03a-readers-writers.cpp
  type GlobalData (line 15) | struct GlobalData {
  type ThreadArg (line 25) | struct ThreadArg {
  function prepareArg (line 90) | void prepareArg(ThreadArg arg[], int numArg, GlobalData* g) {
  function main (line 99) | int main() {

FILE: cpp/cpp-pthread/exer03b-readers-writers.cpp
  type GlobalData (line 15) | struct GlobalData {
  type ThreadArg (line 27) | struct ThreadArg {
  function prepareArg (line 98) | void prepareArg(ThreadArg arg[], int numArg, GlobalData* g) {
  function main (line 107) | int main() {

FILE: cpp/cpp-pthread/exer04-dining-philosophers.cpp
  type TaskArg (line 13) | struct TaskArg {
  function main (line 44) | int main() {

FILE: cpp/cpp-pthread/exer05-util.hpp
  type WorkerScProdArg (line 6) | struct WorkerScProdArg {

FILE: cpp/cpp-pthread/exer05a-product-matrix-vector.cpp
  function getProduct (line 19) | void getProduct(const matrix& mat, const vectord& vec, vectord& result) {
  function main (line 47) | int main() {

FILE: cpp/cpp-pthread/exer05b-product-matrix-matrix.cpp
  function getTransposeMatrix (line 19) | void getTransposeMatrix(const matrix& input, matrix& output) {
  function displayMatrix (line 33) | void displayMatrix(const matrix& mat) {
  function getProduct (line 47) | void getProduct(const matrix& matA, const matrix& matB, matrix& result) {
  function main (line 88) | int main() {

FILE: cpp/cpp-pthread/exer06a-blocking-queue.cpp
  function put (line 17) | class SynchronousQueue {
  function T (line 45) | T take() {
  function main (line 90) | int main() {

FILE: cpp/cpp-pthread/exer06b01-blocking-queue.cpp
  class BlockingQueue (line 20) | class BlockingQueue {
    method BlockingQueue (line 33) | BlockingQueue(int capacity) {
    method put (line 51) | void put(const T& value) {
    method T (line 64) | T take() {
  function main (line 121) | int main() {

FILE: cpp/cpp-pthread/exer06b02-blocking-queue.cpp
  class BlockingQueue (line 19) | class BlockingQueue {
    method BlockingQueue (line 31) | BlockingQueue(int capacity) {
    method put (line 46) | void put(const T& value) {
    method T (line 63) | T take() {
  function main (line 124) | int main() {

FILE: cpp/cpp-pthread/exer07a-data-server.cpp
  type Counter (line 16) | struct Counter {
    method Counter (line 20) | Counter(int value) : value(value) { }
  type ProcessFilesArg (line 25) | struct ProcessFilesArg {
  function checkAuthUser (line 32) | void checkAuthUser() {
  function processRequest (line 70) | void processRequest() {
  function main (line 100) | int main() {

FILE: cpp/cpp-pthread/exer07b-data-server.cpp
  type ProcessFilesArg (line 16) | struct ProcessFilesArg {
  function checkAuthUser (line 23) | void checkAuthUser() {
  function processRequest (line 56) | void processRequest() {
  function main (line 82) | int main() {

FILE: cpp/cpp-pthread/exer07c-data-server.cpp
  type ProcessFilesArg (line 16) | struct ProcessFilesArg {
  function checkAuthUser (line 23) | void checkAuthUser() {
  function processRequest (line 56) | void processRequest() {
  function main (line 78) | int main() {

FILE: cpp/cpp-pthread/exer07d-data-server.cpp
  type ProcessFilesArg (line 16) | struct ProcessFilesArg {
  function checkAuthUser (line 23) | void checkAuthUser() {
  function processRequest (line 56) | void processRequest() {
  function main (line 80) | int main() {

FILE: cpp/cpp-pthread/exer08-exec-service-itask.hpp
  class ITask (line 7) | class ITask {

FILE: cpp/cpp-pthread/exer08-exec-service-main.cpp
  class MyTask (line 18) | class MyTask : public ITask {
    method run (line 23) | void run() override {
  function main (line 32) | int main() {

FILE: cpp/cpp-pthread/exer08-exec-service-v0a.hpp
  class MyExecServiceV0A (line 24) | class MyExecServiceV0A {
    method MyExecServiceV0A (line 33) | MyExecServiceV0A(int numThreads) {
    method MyExecServiceV0A (line 38) | MyExecServiceV0A(const MyExecServiceV0A& other) = delete;
    method MyExecServiceV0A (line 39) | MyExecServiceV0A(const MyExecServiceV0A&& other) = delete;
    method init (line 45) | void init(int numThreads) {
    method submit (line 56) | void submit(ITask* task) {
    method waitTaskDone (line 61) | void waitTaskDone() {
    method shutdown (line 68) | void shutdown() {

FILE: cpp/cpp-pthread/exer08-exec-service-v0b.hpp
  class MyExecServiceV0B (line 25) | class MyExecServiceV0B {
    method run (line 37) | void run() override { }
    method MyExecServiceV0B (line 43) | MyExecServiceV0B(int numThreads) {
    method MyExecServiceV0B (line 48) | MyExecServiceV0B(const MyExecServiceV0B& other) = delete;
    method MyExecServiceV0B (line 49) | MyExecServiceV0B(const MyExecServiceV0B&& other) = delete;
    method init (line 55) | void init(int numThreads) {
    method submit (line 68) | void submit(ITask* task) {
    method waitTaskDone (line 73) | void waitTaskDone() {
    method shutdown (line 84) | void shutdown() {

FILE: cpp/cpp-pthread/exer08-exec-service-v1a.hpp
  class MyExecServiceV1A (line 24) | class MyExecServiceV1A {
    method MyExecServiceV1A (line 40) | MyExecServiceV1A(int numThreads) {
    method MyExecServiceV1A (line 45) | MyExecServiceV1A(const MyExecServiceV1A& other) = delete;
    method MyExecServiceV1A (line 46) | MyExecServiceV1A(const MyExecServiceV1A&& other) = delete;
    method init (line 52) | void init(int numThreads) {
    method submit (line 70) | void submit(ITask* task) {
    method waitTaskDone (line 79) | void waitTaskDone() {
    method shutdown (line 102) | void shutdown() {

FILE: cpp/cpp-pthread/exer08-exec-service-v1b.hpp
  class MyExecServiceV1B (line 22) | class MyExecServiceV1B {
    method MyExecServiceV1B (line 40) | MyExecServiceV1B(int numThreads) {
    method MyExecServiceV1B (line 45) | MyExecServiceV1B(const MyExecServiceV1B& other) = delete;
    method MyExecServiceV1B (line 46) | MyExecServiceV1B(const MyExecServiceV1B&& other) = delete;
    method init (line 52) | void init(int numThreads) {
    method submit (line 73) | void submit(ITask* task) {
    method waitTaskDone (line 82) | void waitTaskDone() {
    method shutdown (line 109) | void shutdown() {

FILE: cpp/cpp-pthread/exer08-exec-service-v2a.hpp
  class MyExecServiceV2A (line 24) | class MyExecServiceV2A {
    method MyExecServiceV2A (line 42) | MyExecServiceV2A(int numThreads) {
    method MyExecServiceV2A (line 47) | MyExecServiceV2A(const MyExecServiceV2A& other) = delete;
    method MyExecServiceV2A (line 48) | MyExecServiceV2A(const MyExecServiceV2A&& other) = delete;
    method init (line 54) | void init(int numThreads) {
    method submit (line 74) | void submit(ITask* task) {
    method waitTaskDone (line 83) | void waitTaskDone() {
    method shutdown (line 106) | void shutdown() {

FILE: cpp/cpp-pthread/exer08-exec-service-v2b.hpp
  class MyExecServiceV2B (line 23) | class MyExecServiceV2B {
    method MyExecServiceV2B (line 41) | MyExecServiceV2B(int numThreads) {
    method MyExecServiceV2B (line 46) | MyExecServiceV2B(const MyExecServiceV2B& other) = delete;
    method MyExecServiceV2B (line 47) | MyExecServiceV2B(const MyExecServiceV2B&& other) = delete;
    method init (line 53) | void init(int numThreads) {
    method submit (line 73) | void submit(ITask* task) {
    method waitTaskDone (line 82) | void waitTaskDone() {
    method shutdown (line 108) | void shutdown() {

FILE: cpp/cpp-pthread/exerex-countdown-timer-a.cpp
  function waitForTime (line 34) | bool waitForTime(const int waitTime) {
  function main (line 57) | int main() {

FILE: cpp/cpp-pthread/exerex-countdown-timer-b.cpp
  function main (line 27) | int main() {

FILE: cpp/cpp-pthread/mylib-blockingqueue.hpp
  type mylib (line 27) | namespace mylib
    class BlockingQueue (line 33) | class BlockingQueue {
      type PendingData (line 43) | struct PendingData {
        method PendingData (line 47) | PendingData(BlockingQueue<T> * thisPtr, const T data)
      method BlockingQueue (line 53) | BlockingQueue() : capacity(std::numeric_limits<size_t>::max()) {
      method BlockingQueue (line 57) | BlockingQueue(size_t capacity) : capacity(capacity) {
      method BlockingQueue (line 68) | BlockingQueue(const BlockingQueue& other) = delete;
      method BlockingQueue (line 69) | BlockingQueue(const BlockingQueue&& other) = delete;
      method empty (line 74) | bool empty() const {
      method size (line 79) | size_t size() const {
      method put (line 85) | void put(const T& value) {
      method T (line 102) | T take() {
      method add (line 124) | void add(const T& value) {
      method peek (line 136) | bool peek(T& result) const {
      method clear (line 152) | void clear() {

FILE: cpp/cpp-pthread/mylib-execservice.hpp
  type mylib (line 33) | namespace mylib {
    class ExecService (line 37) | class ExecService {
      method ExecService (line 59) | ExecService(int numThreads) {
      method ExecService (line 64) | ExecService(const ExecService& other) = delete;
      method ExecService (line 65) | ExecService(const ExecService&& other) = delete;
      method init (line 71) | void init(int numThreads) {
      method submit (line 92) | void submit(taskFunc task) {
      method waitTaskDone (line 101) | void waitTaskDone() {
      method shutdown (line 128) | void shutdown() {

FILE: cpp/cpp-pthread/mylib-latch.hpp
  type mylib (line 25) | namespace mylib {
    class CountDownLatch (line 29) | class CountDownLatch {
      method CountDownLatch (line 38) | CountDownLatch(unsigned int count) {
      method CountDownLatch (line 50) | CountDownLatch(const CountDownLatch& other) = delete;
      method CountDownLatch (line 51) | CountDownLatch(const CountDownLatch&& other) = delete;
      method getCount (line 57) | int getCount() const {
      method countDown (line 62) | void countDown() {
      method wait (line 79) | void wait() {

FILE: cpp/cpp-std/demo00.cpp
  function doTask (line 13) | void doTask() {
  function main (line 20) | int main() {

FILE: cpp/cpp-std/demo01a01-hello.cpp
  function doTask (line 13) | void doTask() {
  function main (line 19) | int main() {

FILE: cpp/cpp-std/demo01a02-hello.cpp
  function doTask (line 13) | void doTask(char const* message, int number) {
  function main (line 19) | int main() {

FILE: cpp/cpp-std/demo01b-hello-class01.cpp
  class Example (line 14) | class Example {
    method doTask (line 16) | void doTask(string message) {
  function main (line 23) | int main() {

FILE: cpp/cpp-std/demo01b-hello-class02.cpp
  class Example (line 14) | class Example {
    method run (line 16) | void run() {
    method doTask (line 22) | void doTask(string message) {
  function main (line 29) | int main() {

FILE: cpp/cpp-std/demo01b-hello-class03.cpp
  class Example (line 14) | class Example {
    method run (line 16) | void run() {
    method doTask (line 22) | static void doTask(string message) {
  function main (line 29) | int main() {

FILE: cpp/cpp-std/demo01b-hello-functor.cpp
  class Example (line 14) | class Example {
  function main (line 23) | int main() {

FILE: cpp/cpp-std/demo01c-hello-lambda.cpp
  function main (line 14) | int main() {

FILE: cpp/cpp-std/demo02-join.cpp
  function doHeavyTask (line 12) | void doHeavyTask() {
  function main (line 21) | int main() {

FILE: cpp/cpp-std/demo03a-pass-arg.cpp
  type Point (line 15) | struct Point {
    method Point (line 19) | Point(int x, int y): x(x), y(y) { }
  function doTask (line 24) | void doTask(int a, double b, string c, char const* d, Point e) {
  function main (line 32) | int main() {

FILE: cpp/cpp-std/demo03b-pass-arg.cpp
  function doTask (line 14) | void doTask(const string& msg) {
  function main (line 20) | int main() {

FILE: cpp/cpp-std/demo03c-pass-arg.cpp
  function doTask (line 26) | void doTask(string& msg) {
  function main (line 32) | int main() {

FILE: cpp/cpp-std/demo04a-sleep.cpp
  function doTask (line 15) | void doTask(string name) {
  function main (line 23) | int main() {

FILE: cpp/cpp-std/demo04b-sleep.cpp
  function doTask (line 20) | void doTask(string name, sysclock::time_point tpWakeUp) {
  function main (line 27) | int main() {

FILE: cpp/cpp-std/demo05-id.cpp
  function doTask (line 13) | void doTask() {
  function main (line 20) | int main() {

FILE: cpp/cpp-std/demo06a-list-threads.cpp
  function doTask (line 13) | void doTask(int index) {
  function main (line 19) | int main() {

FILE: cpp/cpp-std/demo06b-list-threads.cpp
  function doTask (line 14) | void doTask(int index) {
  function main (line 20) | int main() {

FILE: cpp/cpp-std/demo07-terminate.cpp
  function doTask (line 17) | void doTask() {
  function main (line 26) | int main() {

FILE: cpp/cpp-std/demo08a-return-value.cpp
  function doubleValue (line 13) | void doubleValue(int arg, int* res) {
  function squareValue (line 19) | void squareValue(int arg, int& res) {
  function main (line 25) | int main() {

FILE: cpp/cpp-std/demo08b-return-value.cpp
  function doubleValue (line 15) | void doubleValue(int arg, std::promise<int> & prom) {
  function main (line 27) | int main() {

FILE: cpp/cpp-std/demo08c-return-value.cpp
  function string (line 17) | string doubleValue(int arg) {
  function main (line 27) | int main() {

FILE: cpp/cpp-std/demo09-detach.cpp
  function foo (line 13) | void foo() {
  function main (line 23) | int main() {

FILE: cpp/cpp-std/demo10-yield.cpp
  function littleSleep (line 19) | void littleSleep(int us) {
  function main (line 31) | int main() {

FILE: cpp/cpp-std/demo11a-exec-service.cpp
  function doTask (line 15) | void doTask() {
  class MyFunctor (line 21) | class MyFunctor {
  function main (line 30) | int main() {

FILE: cpp/cpp-std/demo11b-exec-service.cpp
  function main (line 17) | int main() {

FILE: cpp/cpp-std/demo12a-race-condition.cpp
  function doTask (line 14) | void doTask(int index) {
  function main (line 21) | int main() {

FILE: cpp/cpp-std/demo12b01-data-race-single.cpp
  function getResult (line 14) | int getResult(int N) {
  function main (line 29) | int main() {

FILE: cpp/cpp-std/demo12b02-data-race-multi.cpp
  function markDiv2 (line 15) | void markDiv2(vector<bool> & a, int N) {
  function markDiv3 (line 22) | void markDiv3(vector<bool> & a, int N) {
  function main (line 29) | int main() {

FILE: cpp/cpp-std/demo12c01-race-cond-data-race.cpp
  function increaseCounter (line 17) | void increaseCounter() {
  function main (line 27) | int main() {

FILE: cpp/cpp-std/demo12c02-race-cond-data-race.cpp
  function doTaskA (line 21) | void doTaskA(sysclock::time_point timePointWakeUp) {
  function doTaskB (line 32) | void doTaskB(sysclock::time_point timePointWakeUp) {
  function main (line 43) | int main() {

FILE: cpp/cpp-std/demo13a-mutex.cpp
  function doTask (line 19) | void doTask() {
  function main (line 32) | int main() {

FILE: cpp/cpp-std/demo13b01-mutex.cpp
  function doTask (line 23) | void doTask() {
  function main (line 37) | int main() {

FILE: cpp/cpp-std/demo13b02-mutex.cpp
  function doTask (line 28) | void doTask() {
  function main (line 44) | int main() {

FILE: cpp/cpp-std/demo13c-mutex-trylock.cpp
  function doTask (line 20) | void doTask() {
  function main (line 35) | int main() {

FILE: cpp/cpp-std/demo14-synchronized-block.cpp
  function doTask (line 31) | void doTask() {
  function main (line 45) | int main() {

FILE: cpp/cpp-std/demo15a-deadlock.cpp
  function doTask (line 19) | void doTask(std::string name) {
  function main (line 29) | int main() {

FILE: cpp/cpp-std/demo15b-deadlock.cpp
  function foo (line 20) | void foo() {
  function bar (line 35) | void bar() {
  function main (line 50) | int main() {

FILE: cpp/cpp-std/demo16-monitor.cpp
  class Monitor (line 15) | class Monitor {
    method init (line 25) | void init(int* pCounter) {
    method increaseCounter (line 30) | void increaseCounter() {
  function doTask (line 39) | void doTask(Monitor* monitor) {
  function main (line 48) | int main() {

FILE: cpp/cpp-std/demo17a-reentrant-lock.cpp
  function doTask (line 18) | void doTask() {
  function main (line 31) | int main() {

FILE: cpp/cpp-std/demo17b-reentrant-lock.cpp
  function doTask (line 18) | void doTask() {
  function doTaskUsingSyncBlock (line 31) | void doTaskUsingSyncBlock() {
  function main (line 45) | int main() {

FILE: cpp/cpp-std/demo17c-reentrant-lock.cpp
  function doTask (line 19) | void doTask(char name) {
  function doTaskUsingSyncBlock (line 34) | void doTaskUsingSyncBlock(char name) {
  function main (line 52) | int main() {

FILE: cpp/cpp-std/demo18a01-barrier.cpp
  function processRequest (line 21) | void processRequest(string userName, int waitTime) {
  function main (line 35) | int main() {

FILE: cpp/cpp-std/demo18a02-barrier.cpp
  function processRequest (line 21) | void processRequest(string userName, int waitTime) {
  function main (line 35) | int main() {

FILE: cpp/cpp-std/demo18a03-barrier.cpp
  function processRequest (line 22) | void processRequest(string userName, int waitTime) {
  function main (line 36) | int main() {

FILE: cpp/cpp-std/demo18b01-latch.cpp
  function processRequest (line 21) | void processRequest(string userName, int waitTime) {
  function main (line 33) | int main() {

FILE: cpp/cpp-std/demo18b02-latch.cpp
  function doTask (line 24) | void doTask(string message, int waitTime) {
  function main (line 36) | int main() {

FILE: cpp/cpp-std/demo19a-read-write-lock.cpp
  function readFunc (line 21) | void readFunc(int waitTime) {
  function writeFunc (line 33) | void writeFunc(int waitTime) {
  function main (line 46) | int main() {

FILE: cpp/cpp-std/demo19b-read-write-lock.cpp
  function readFunc (line 21) | void readFunc(int waitTime) {
  function writeFunc (line 33) | void writeFunc(int waitTime) {
  function main (line 47) | int main() {

FILE: cpp/cpp-std/demo20a01-semaphore.cpp
  function makeOneSheet (line 19) | void makeOneSheet() {
  function combineOnePackage (line 29) | void combineOnePackage() {
  function main (line 39) | int main() {

FILE: cpp/cpp-std/demo20a02-semaphore.cpp
  function makeOneSheet (line 20) | void makeOneSheet() {
  function combineOnePackage (line 30) | void combineOnePackage() {
  function main (line 45) | int main() {

FILE: cpp/cpp-std/demo20a03-semaphore-deadlock.cpp
  function makeOneSheet (line 20) | void makeOneSheet() {
  function combineOnePackage (line 30) | void combineOnePackage() {
  function main (line 45) | int main() {

FILE: cpp/cpp-std/demo20b-semaphore.cpp
  function makeTire (line 20) | void makeTire() {
  function makeChassis (line 33) | void makeChassis() {
  function main (line 52) | int main() {

FILE: cpp/cpp-std/demo21a01-condition-variable.cpp
  function foo (line 20) | void foo() {
  function bar (line 31) | void bar() {
  function main (line 38) | int main() {

FILE: cpp/cpp-std/demo21a02-condition-variable.cpp
  function foo (line 22) | void foo() {
  function bar (line 33) | void bar() {
  function main (line 42) | int main() {

FILE: cpp/cpp-std/demo21a03-condition-variable.cpp
  function foo (line 22) | void foo() {
  function bar (line 33) | void bar() {
  function main (line 41) | int main() {

FILE: cpp/cpp-std/demo21b-condition-variable.cpp
  function foo (line 26) | void foo() {
  function egg (line 47) | void egg() {
  function main (line 69) | int main() {

FILE: cpp/cpp-std/demo22a-blocking-queue.cpp
  function producer (line 20) | void producer(BlockingQueue<string>* blkQueue) {
  function consumer (line 33) | void consumer(BlockingQueue<string>* blkQueue) {
  function main (line 45) | int main() {

FILE: cpp/cpp-std/demo22b-blocking-queue.cpp
  function producer (line 20) | void producer(BlockingQueue<string>* blkQueue) {
  function consumer (line 34) | void consumer(BlockingQueue<string>* blkQueue) {
  function main (line 47) | int main() {

FILE: cpp/cpp-std/demo23a01-thread-local.cpp
  function doTask (line 19) | void doTask() {
  function main (line 25) | int main() {

FILE: cpp/cpp-std/demo23a02-thread-local.cpp
  function string (line 20) | string getValue() {
  function doTask (line 30) | void doTask() {
  function main (line 36) | int main() {

FILE: cpp/cpp-std/demo23b-thread-local.cpp
  function doTask (line 19) | void doTask(int t) {
  function main (line 30) | int main() {

FILE: cpp/cpp-std/demo24-volatile.cpp
  function doTask (line 17) | void doTask() {
  function main (line 26) | int main() {

FILE: cpp/cpp-std/demo25a-atomic.cpp
  function doTask (line 18) | void doTask() {
  function main (line 25) | int main() {

FILE: cpp/cpp-std/demo25b-atomic.cpp
  function doTask (line 20) | void doTask() {
  function main (line 27) | int main() {

FILE: cpp/cpp-std/demo25c-atomic-gcc.cpp
  function doTask (line 28) | void doTask() {
  function main (line 38) | int main() {

FILE: cpp/cpp-std/demoex-async-future.cpp
  function main (line 11) | int main() {

FILE: cpp/cpp-std/demoex-jthread.cpp
  function sumIntegers (line 17) | void sumIntegers(int a, int b) {
  function iterateValues (line 24) | void iterateValues(std::stop_token stopTok, int startValue, int endValue) {
  function main (line 39) | int main() {

FILE: cpp/cpp-std/exer01a-max-div.cpp
  function main (line 12) | int main() {

FILE: cpp/cpp-std/exer01b-max-div.cpp
  type WorkerArg (line 15) | struct WorkerArg {
    method WorkerArg (line 19) | WorkerArg(int iStart = 0, int iEnd = 0): iStart(iStart), iEnd(iEnd)
  type WorkerResult (line 26) | struct WorkerResult {
    method WorkerResult (line 30) | WorkerResult(int value = 0, int numDiv = 0): value(value), numDiv(numDiv)
  function workerFunc (line 37) | void workerFunc(WorkerArg* arg, WorkerResult* res) {
  function prepare (line 59) | void prepare(
  function main (line 87) | int main() {

FILE: cpp/cpp-std/exer01c-max-div.cpp
  type WorkerArg (line 16) | struct WorkerArg {
    method WorkerArg (line 20) | WorkerArg(int iStart = 0, int iEnd = 0): iStart(iStart), iEnd(iEnd)
  class FinalResult (line 27) | class FinalResult {
    method update (line 37) | void update(int value, int numDiv) {
  function workerFunc (line 50) | void workerFunc(WorkerArg* arg, FinalResult* res) {
  function prepare (line 72) | void prepare(
  function main (line 98) | int main() {

FILE: cpp/cpp-std/exer02a01-producer-consumer.cpp
  function producer (line 18) | void producer(BlockingQueue<int>* blkq) {
  function consumer (line 29) | void consumer(BlockingQueue<int>* blkq) {
  function main (line 40) | int main() {

FILE: cpp/cpp-std/exer02a02-producer-consumer.cpp
  function producer (line 18) | void producer(BlockingQueue<int>* blkq) {
  function consumer (line 29) | void consumer(BlockingQueue<int>* blkq) {
  function main (line 40) | int main() {

FILE: cpp/cpp-std/exer02a03-producer-consumer.cpp
  function producer (line 19) | void producer(BlockingQueue<int>* blkq) {
  function consumer (line 30) | void consumer(string name, BlockingQueue<int>* blkq) {
  function main (line 41) | int main() {

FILE: cpp/cpp-std/exer02a04-producer-consumer.cpp
  function producer (line 18) | void producer(BlockingQueue<int>* blkq, int startValue) {
  function consumer (line 28) | void consumer(BlockingQueue<int>* blkq) {
  function main (line 40) | int main() {

FILE: cpp/cpp-std/exer02b01-producer-consumer.cpp
  function producer (line 22) | void producer(
  function consumer (line 41) | void consumer(
  function main (line 62) | int main() {

FILE: cpp/cpp-std/exer02b02-producer-consumer.cpp
  function producer (line 22) | void producer(
  function consumer (line 42) | void consumer(
  function main (line 63) | int main() {

FILE: cpp/cpp-std/exer02b03-producer-consumer.cpp
  function producer (line 22) | void producer(
  function consumer (line 39) | void consumer(
  function main (line 61) | int main() {

FILE: cpp/cpp-std/exer02b04-producer-consumer.cpp
  function producer (line 22) | void producer(
  function consumer (line 39) | void consumer(
  function main (line 61) | int main() {

FILE: cpp/cpp-std/exer02c-producer-consumer.cpp
  class Monitor (line 20) | class Monitor {
    method Monitor (line 31) | Monitor() = default;
    method Monitor (line 32) | Monitor(const Monitor& other) = delete;
    method Monitor (line 33) | Monitor(const Monitor&& other) = delete;
    method init (line 38) | void init(int maxQueueSize, std::queue<T>* q) {
    method add (line 44) | void add(const T& item) {
    method T (line 61) | T remove() {
  function producer (line 84) | void producer(Monitor<T>* monitor, int startValue) {
  function consumer (line 95) | void consumer(Monitor<T>* monitor) {
  function main (line 107) | int main() {

FILE: cpp/cpp-std/exer03a-readers-writers.cpp
  type GlobalData (line 16) | struct GlobalData {
  function doTaskWriter (line 26) | void doTaskWriter(GlobalData* g, int delayTime) {
  function doTaskReader (line 39) | void doTaskReader(GlobalData* g, int delayTime) {
  function main (line 69) | int main() {

FILE: cpp/cpp-std/exer03b-readers-writers.cpp
  type GlobalData (line 16) | struct GlobalData {
  function doTaskWriter (line 28) | void doTaskWriter(GlobalData* g, int delayTime) {
  function doTaskReader (line 45) | void doTaskReader(GlobalData* g, int delayTime) {
  function main (line 81) | int main() {

FILE: cpp/cpp-std/exer04-dining-philosophers.cpp
  function doTaskPhilosopher (line 14) | void doTaskPhilosopher(std::mutex chopstick[], int numPhilo, int idPhilo) {
  function doTaskPhilosopherUsingSyncBlock (line 31) | void doTaskPhilosopherUsingSyncBlock(std::mutex chopstick[], int numPhil...
  function main (line 46) | int main() {

FILE: cpp/cpp-std/exer05-util.hpp
  function getScalarProduct (line 6) | void getScalarProduct(double const* u, double const* v, int sizeVector, ...

FILE: cpp/cpp-std/exer05a-product-matrix-vector.cpp
  function getProduct (line 19) | void getProduct(const matrix& mat, const vectord& vec, vectord& result) {
  function main (line 43) | int main() {

FILE: cpp/cpp-std/exer05b-product-matrix-matrix.cpp
  function getTransposeMatrix (line 19) | void getTransposeMatrix(const matrix& input, matrix& output) {
  function displayMatrix (line 33) | void displayMatrix(const matrix& mat) {
  function getProduct (line 47) | void getProduct(const matrix& matA, const matrix& matB, matrix& result) {
  function main (line 81) | int main() {

FILE: cpp/cpp-std/exer06a-blocking-queue.cpp
  class SynchronousQueue (line 21) | class SynchronousQueue {
    method put (line 30) | void put(const T& value) {
    method T (line 37) | T take() {
  function producer (line 48) | void producer(SynchronousQueue<std::string>* syncQueue) {
  function consumer (line 60) | void consumer(SynchronousQueue<std::string>* syncQueue) {
  function main (line 72) | int main() {

FILE: cpp/cpp-std/exer06b01-blocking-queue.cpp
  class BlockingQueue (line 25) | class BlockingQueue {
    method BlockingQueue (line 38) | BlockingQueue(int capacity) : capacity(capacity), semRemain(capacity),...
    method put (line 44) | void put(const T& value) {
    method T (line 56) | T take() {
  function producer (line 74) | void producer(BlockingQueue<std::string>* blkQueue) {
  function consumer (line 86) | void consumer(BlockingQueue<std::string>* blkQueue) {
  function main (line 101) | int main() {

FILE: cpp/cpp-std/exer06b02-blocking-queue.cpp
  class BlockingQueue (line 21) | class BlockingQueue {
    method BlockingQueue (line 33) | BlockingQueue(int capacity) {
    method put (line 41) | void put(const T& value) {
    method T (line 57) | T take() {
  function producer (line 80) | void producer(BlockingQueue<std::string>* blkQueue) {
  function consumer (line 92) | void consumer(BlockingQueue<std::string>* blkQueue) {
  function main (line 107) | int main() {

FILE: cpp/cpp-std/exer07a-data-server.cpp
  type Counter (line 23) | struct Counter {
    method Counter (line 27) | Counter(int value) : value(value) { }
  function checkAuthUser (line 32) | void checkAuthUser() {
  function processFiles (line 41) | void processFiles(const vector<string>& lstFileName, Counter& counter) {
  function processRequest (line 62) | void processRequest() {
  function main (line 86) | int main() {

FILE: cpp/cpp-std/exer07b-data-server.cpp
  function checkAuthUser (line 24) | void checkAuthUser() {
  function processFiles (line 33) | void processFiles(const vector<string>& lstFileName, cntsemaphore& sem) {
  function processRequest (line 50) | void processRequest() {
  function main (line 71) | int main() {

FILE: cpp/cpp-std/exer07c-data-server.cpp
  function checkAuthUser (line 22) | void checkAuthUser() {
  function processFiles (line 31) | void processFiles(const vector<string>& lstFileName, std::latch& rdLatch) {
  function processRequest (line 48) | void processRequest() {
  function main (line 67) | int main() {

FILE: cpp/cpp-std/exer07d-data-server.cpp
  function checkAuthUser (line 22) | void checkAuthUser() {
  function processFiles (line 31) | void processFiles(const vector<string>& lstFileName, mylib::BlockingQueu...
  function processRequest (line 48) | void processRequest() {
  function main (line 69) | int main() {

FILE: cpp/cpp-std/exer08-exec-service-itask.hpp
  class ITask (line 7) | class ITask {

FILE: cpp/cpp-std/exer08-exec-service-main.cpp
  class MyTask (line 18) | class MyTask : public ITask {
    method run (line 23) | void run() override {
  function main (line 32) | int main() {

FILE: cpp/cpp-std/exer08-exec-service-v0a.hpp
  class MyExecServiceV0A (line 24) | class MyExecServiceV0A {
    method MyExecServiceV0A (line 33) | MyExecServiceV0A(int numThreads) {
    method MyExecServiceV0A (line 38) | MyExecServiceV0A(const MyExecServiceV0A& other) = delete;
    method MyExecServiceV0A (line 39) | MyExecServiceV0A(const MyExecServiceV0A&& other) = delete;
    method init (line 45) | void init(int numThreads) {
    method submit (line 56) | void submit(ITask* task) {
    method waitTaskDone (line 61) | void waitTaskDone() {
    method shutdown (line 68) | void shutdown() {
    method threadWorkerFunc (line 77) | static void threadWorkerFunc(MyExecServiceV0A* thisPtr) {

FILE: cpp/cpp-std/exer08-exec-service-v0b.hpp
  class MyExecServiceV0B (line 26) | class MyExecServiceV0B {
    method run (line 38) | void run() override { }
    method MyExecServiceV0B (line 44) | MyExecServiceV0B(int numThreads) {
    method MyExecServiceV0B (line 49) | MyExecServiceV0B(const MyExecServiceV0B& other) = delete;
    method MyExecServiceV0B (line 50) | MyExecServiceV0B(const MyExecServiceV0B&& other) = delete;
    method init (line 56) | void init(int numThreads) {
    method submit (line 69) | void submit(ITask* task) {
    method waitTaskDone (line 74) | void waitTaskDone() {
    method shutdown (line 84) | void shutdown() {
    method threadWorkerFunc (line 103) | static void threadWorkerFunc(MyExecServiceV0B* thisPtr) {

FILE: cpp/cpp-std/exer08-exec-service-v1a.hpp
  class MyExecServiceV1A (line 26) | class MyExecServiceV1A {
    method MyExecServiceV1A (line 46) | MyExecServiceV1A(int numThreads) {
    method MyExecServiceV1A (line 51) | MyExecServiceV1A(const MyExecServiceV1A& other) = delete;
    method MyExecServiceV1A (line 52) | MyExecServiceV1A(const MyExecServiceV1A&& other) = delete;
    method init (line 58) | void init(int numThreads) {
    method submit (line 73) | void submit(ITask* task) {
    method waitTaskDone (line 83) | void waitTaskDone() {
    method shutdown (line 105) | void shutdown() {
    method threadWorkerFunc (line 124) | static void threadWorkerFunc(MyExecServiceV1A* thisPtr) {

FILE: cpp/cpp-std/exer08-exec-service-v1b.hpp
  class MyExecServiceV1B (line 24) | class MyExecServiceV1B {
    method MyExecServiceV1B (line 46) | MyExecServiceV1B(int numThreads) {
    method MyExecServiceV1B (line 51) | MyExecServiceV1B(const MyExecServiceV1B& other) = delete;
    method MyExecServiceV1B (line 52) | MyExecServiceV1B(const MyExecServiceV1B&& other) = delete;
    method init (line 58) | void init(int numThreads) {
    method submit (line 73) | void submit(ITask* task) {
    method waitTaskDone (line 83) | void waitTaskDone() {
    method shutdown (line 100) | void shutdown() {
    method threadWorkerFunc (line 119) | static void threadWorkerFunc(MyExecServiceV1B* thisPtr) {

FILE: cpp/cpp-std/exer08-exec-service-v2a.hpp
  class MyExecServiceV2A (line 26) | class MyExecServiceV2A {
    method MyExecServiceV2A (line 49) | MyExecServiceV2A(int numThreads) {
    method MyExecServiceV2A (line 54) | MyExecServiceV2A(const MyExecServiceV2A& other) = delete;
    method MyExecServiceV2A (line 55) | MyExecServiceV2A(const MyExecServiceV2A&& other) = delete;
    method init (line 61) | void init(int numThreads) {
    method submit (line 75) | void submit(ITask* task) {
    method waitTaskDone (line 85) | void waitTaskDone() {
    method shutdown (line 101) | void shutdown() {
    method threadWorkerFunc (line 120) | static void threadWorkerFunc(MyExecServiceV2A* thisPtr) {

FILE: cpp/cpp-std/exer08-exec-service-v2b.hpp
  class MyExecServiceV2B (line 25) | class MyExecServiceV2B {
    method MyExecServiceV2B (line 47) | MyExecServiceV2B(int numThreads) {
    method MyExecServiceV2B (line 52) | MyExecServiceV2B(const MyExecServiceV2B& other) = delete;
    method MyExecServiceV2B (line 53) | MyExecServiceV2B(const MyExecServiceV2B&& other) = delete;
    method init (line 59) | void init(int numThreads) {
    method submit (line 73) | void submit(ITask* task) {
    method waitTaskDone (line 83) | void waitTaskDone() {
    method shutdown (line 100) | void shutdown() {
    method threadWorkerFunc (line 119) | static void threadWorkerFunc(MyExecServiceV2B* thisPtr) {

FILE: cpp/cpp-std/exerex-countdown-timer.cpp
  function doUserInput (line 15) | void doUserInput(char* buffer, std::condition_variable* cv) {
  function waitForTime (line 25) | bool waitForTime(const int waitTime, std::condition_variable& cv, std::m...
  function main (line 37) | int main() {

FILE: cpp/cpp-std/mylib-blockingqueue.hpp
  type mylib (line 29) | namespace mylib
    class BlockingQueue (line 35) | class BlockingQueue {
      method BlockingQueue (line 51) | BlockingQueue() : capacity(std::numeric_limits<size_t>::max()) {
      method BlockingQueue (line 55) | BlockingQueue(size_t capacity) : capacity(capacity) {
      method BlockingQueue (line 59) | BlockingQueue(const BlockingQueue& other) = delete;
      method BlockingQueue (line 60) | BlockingQueue(const BlockingQueue&& other) = delete;
      method empty (line 65) | bool empty() const {
      method size (line 70) | size_t size() const {
      method put (line 76) | void put(const T& value) {
      method T (line 85) | T take() {
      method add (line 96) | void add(const T& value) {
      method peek (line 104) | bool peek(T& result) const {
      method clear (line 115) | void clear() {

FILE: cpp/cpp-std/mylib-execservice.hpp
  type mylib (line 35) | namespace mylib {
    class ExecService (line 39) | class ExecService {
      method ExecService (line 65) | ExecService(int numThreads) {
      method ExecService (line 70) | ExecService(const ExecService& other) = delete;
      method ExecService (line 71) | ExecService(const ExecService&& other) = delete;
      method init (line 77) | void init(int numThreads) {
      method submit (line 92) | void submit(taskFunc task) {
      method waitTaskDone (line 102) | void waitTaskDone() {
      method shutdown (line 118) | void shutdown() {
      method threadWorkerFunc (line 137) | static void threadWorkerFunc(ExecService* thisPtr) {

FILE: cpp/cpp-std/mylib-random.hpp
  type mylib (line 26) | namespace mylib {
    class RandInt (line 30) | class RandInt {
      method RandInt (line 39) | RandInt() {
      method RandInt (line 44) | RandInt(int minValue, int maxValueInclusive) {
      method init (line 49) | void init(int minValue, int maxValueInclusive) {
      method next (line 55) | int next() {
      method RandInt (line 60) | RandInt(const RandInt& other) = default;
      method RandInt (line 61) | RandInt(RandInt&& other) = default;
      method RandInt (line 62) | RandInt& operator=(const RandInt& other) = default;
      method RandInt (line 63) | RandInt& operator=(RandInt&& other) = default;
      method get (line 71) | static int get(int maxExclusive) {

FILE: cpp/cpp-std/mylib-time.hpp
  type mylib (line 26) | namespace mylib {
    class HiResClock (line 35) | class HiResClock {
      method now (line 42) | static inline stdhrc::time_point now()
      method duType (line 49) | static inline
      method duType (line 61) | static inline
    function getTimePoint (line 82) | class clock::time_point getTimePoint(
    function getTimePointFutureFloor (line 101) | chro::time_point<clock>

FILE: csharp/IRunnable.cs
  type IRunnable (line 1) | interface IRunnable
    method run (line 3) | public abstract void run();

FILE: csharp/Program.cs
  class Program (line 1) | class Program
    method Main (line 3) | static void Main(string[] args)

FILE: csharp/demo/demo00-intro.cs
  class Demo00 (line 10) | class Demo00 : IRunnable
    method run (line 12) | public void run()
    method doTask (line 22) | private void doTask()

FILE: csharp/demo/demo01a-hello.cs
  class Demo01A (line 10) | class Demo01A : IRunnable
    method run (line 12) | public void run()
    method doTask (line 22) | private void doTask()

FILE: csharp/demo/demo01b01-hello.cs
  class Demo01B01 (line 10) | class Demo01B01 : IRunnable
    method run (line 12) | public void run()

FILE: csharp/demo/demo01b02-hello.cs
  class Demo01B02 (line 10) | class Demo01B02 : IRunnable
    method run (line 12) | public void run()

FILE: csharp/demo/demo01ex-name.cs
  class Demo01ExtraName (line 10) | class Demo01ExtraName : IRunnable
    method run (line 12) | public void run()
    method doTask (line 26) | private void doTask()

FILE: csharp/demo/demo02a-join.cs
  class Demo02A (line 9) | class Demo02A : IRunnable
    method run (line 11) | public void run()
    method doHeavyTask (line 21) | private void doHeavyTask() {

FILE: csharp/demo/demo02b-join.cs
  class Demo02B (line 9) | class Demo02B : IRunnable
    method run (line 11) | public void run()

FILE: csharp/demo/demo03a-pass-arg.cs
  class Demo03C (line 10) | class Demo03C : IRunnable
    method run (line 12) | public void run()
    method doTask (line 22) | private void doTask(int a, double b, string c)

FILE: csharp/demo/demo03b-pass-arg.cs
  class Demo03A (line 10) | class Demo03A : IRunnable
    method run (line 12) | public void run()
    method doTask (line 25) | private void doTask(object arg)

FILE: csharp/demo/demo03c-pass-arg.cs
  class Demo03B (line 10) | class Demo03B : IRunnable
    method run (line 12) | public void run()
    method doTask (line 21) | private void doTask(dynamic arg)

FILE: csharp/demo/demo03d-pass-arg.cs
  class Demo03D (line 10) | class Demo03D : IRunnable
    method run (line 12) | public void run()

FILE: csharp/demo/demo04-sleep.cs
  class Demo04 (line 9) | class Demo04 : IRunnable
    method run (line 11) | public void run()

FILE: csharp/demo/demo05-id.cs
  class Demo05 (line 9) | class Demo05 : IRunnable
    method run (line 11) | public void run()

FILE: csharp/demo/demo06a-list-threads.cs
  class Demo06A (line 11) | class Demo06A : IRunnable
    method run (line 13) | public void run()

FILE: csharp/demo/demo06b-list-threads.cs
  class Demo06B (line 11) | class Demo06B : IRunnable
    method run (line 13) | public void run()

FILE: csharp/demo/demo07-terminate.cs
  class Demo07 (line 12) | class Demo07 : IRunnable
    method run (line 16) | public void run()

FILE: csharp/demo/demo08a-return-value.cs
  class Demo08A (line 9) | class Demo08A : IRunnable
    method run (line 11) | public void run()
    method doubleValue (line 30) | private int doubleValue(int value)

FILE: csharp/demo/demo08b-return-value.cs
  class Demo08B (line 10) | class Demo08B : IRunnable
    method run (line 16) | public void run()
    method doubleValue (line 29) | private void doubleValue(int value)

FILE: csharp/demo/demo09-detach.cs
  class Demo09 (line 9) | class Demo09 : IRunnable
    method run (line 11) | public void run()

FILE: csharp/demo/demo10-yield.cs
  class Demo10 (line 9) | class Demo10 : IRunnable
    method run (line 11) | public void run()
    method littleSleep (line 23) | private void littleSleep(double miliseconds)

FILE: csharp/demo/demo11a01-exec-service.cs
  class Demo11A01 (line 11) | class Demo11A01 : IRunnable
    method run (line 13) | public void run()
    method doTask (line 31) | private void doTask(object arg)

FILE: csharp/demo/demo11a02-exec-service.cs
  class Demo11A02 (line 11) | class Demo11A02 : IRunnable
    method run (line 13) | public void run()
    method doTask (line 35) | private void doTask(object arg)

FILE: csharp/demo/demo11a03-exec-service.cs
  class Demo11A03 (line 11) | class Demo11A03 : IRunnable
    method run (line 16) | public void run()
    method getSquared (line 33) | private void getSquared(dynamic arg)

FILE: csharp/demo/demo11a04-exec-service.cs
  class Demo11A04 (line 11) | class Demo11A04 : IRunnable
    method run (line 13) | public void run()

FILE: csharp/demo/demo11a05-exec-service.cs
  class Demo11A05 (line 11) | class Demo11A05 : IRunnable
    method run (line 13) | public void run()

FILE: csharp/demo/demo11b01-exec-service-parallel.cs
  class Demo11B01 (line 11) | class Demo11B01 : IRunnable
    method run (line 13) | public void run()
    method doTask (line 32) | private void doTask(int arg)

FILE: csharp/demo/demo11b02-exec-service-parallel.cs
  class Demo11B02 (line 10) | class Demo11B02 : IRunnable
    method run (line 12) | public void run()

FILE: csharp/demo/demo11c-exec-service.cs
  class Demo11C (line 11) | class Demo11C : IRunnable
    method run (line 13) | public void run()

FILE: csharp/demo/demo12a-race-condition.cs
  class Demo12A (line 10) | class Demo12A : IRunnable
    method run (line 12) | public void run()

FILE: csharp/demo/demo12b01-data-race-single.cs
  class Demo12B01 (line 10) | class Demo12B01 : IRunnable
    method run (line 12) | public void run()
    method getResult (line 20) | private int getResult(int N)

FILE: csharp/demo/demo12b02-data-race-multi.cs
  class Demo12B02 (line 11) | class Demo12B02 : IRunnable
    method run (line 13) | public void run()

FILE: csharp/demo/demo12c01-race-cond-data-race.cs
  class Demo12C01 (line 10) | class Demo12C01 : IRunnable
    method run (line 15) | public void run()
    method doTask (line 36) | private void doTask()

FILE: csharp/demo/demo12c02-race-cond-data-race.cs
  class Demo12C02 (line 9) | class Demo12C02 : IRunnable
    method run (line 11) | public void run()
    class Global (line 40) | class Global

FILE: csharp/demo/demo13a-mutex.cs
  class Demo13A (line 10) | class Demo13A : IRunnable
    method run (line 16) | public void run()
    method doTask (line 40) | private void doTask()

FILE: csharp/demo/demo13b-mutex-trylock.cs
  class Demo13B (line 11) | class Demo13B : IRunnable
    method run (line 17) | public void run()
    method routineCounter (line 40) | private void routineCounter()

FILE: csharp/demo/demo14-synchronized-block.cs
  class Demo14 (line 10) | class Demo14 : IRunnable
    method run (line 16) | public void run()
    method doTask (line 37) | private void doTask()

FILE: csharp/demo/demo15a-deadlock.cs
  class Demo15A (line 10) | class Demo15A : IRunnable
    method run (line 15) | public void run()
    method doTask (line 33) | private void doTask(string name)

FILE: csharp/demo/demo15b-deadlock.cs
  class Demo15B (line 10) | class Demo15B : IRunnable
    method run (line 16) | public void run()

FILE: csharp/demo/demo16-monitor.cs
  class Demo16 (line 16) | class Demo16 : IRunnable
    method run (line 18) | public void run()
    class Counter (line 49) | class Counter
    class MyMonitor (line 56) | class MyMonitor
      method init (line 60) | public void init(Counter counter)
      method increaseCounter (line 65) | public void increaseCounter()

FILE: csharp/demo/demo17a-reentrant-lock.cs
  class Demo17A (line 14) | class Demo17A : IRunnable
    method run (line 16) | public void run()

FILE: csharp/demo/demo17b-reentrant-lock.cs
  class Demo17B (line 11) | class Demo17B : IRunnable
    method run (line 13) | public void run()
    class Worker (line 28) | class Worker
      method Worker (line 35) | public Worker(char name)
      method doTask (line 41) | private void doTask()
      method start (line 56) | public void start()

FILE: csharp/demo/demo18a01-barrier.cs
  class Demo18A01 (line 11) | class Demo18A01 : IRunnable
    method run (line 13) | public void run()
    class ThreadArg (line 44) | class ThreadArg

FILE: csharp/demo/demo18a03-barrier.cs
  class Demo18A03 (line 11) | class Demo18A03 : IRunnable
    method run (line 13) | public void run()
    class ThreadArg (line 46) | class ThreadArg

FILE: csharp/demo/demo18b01-latch.cs
  class Demo18B01 (line 11) | class Demo18B01 : IRunnable
    method run (line 13) | public void run()
    class ThreadArg (line 43) | class ThreadArg

FILE: csharp/demo/demo18b02-latch.cs
  class Demo18B02 (line 13) | class Demo18B02 : IRunnable
    method run (line 15) | public void run()
    class ThreadArg (line 48) | class ThreadArg

FILE: csharp/demo/demo19-read-write-lock.cs
  class Demo19 (line 11) | class Demo19 : IRunnable
    method run (line 13) | public void run()
    class Resource (line 71) | class Resource

FILE: csharp/demo/demo20a01-semaphore.cs
  class Demo20A01 (line 10) | class Demo20A01 : IRunnable
    method run (line 12) | public void run()

FILE: csharp/demo/demo20a02-semaphore.cs
  class Demo20A02 (line 10) | class Demo20A02 : IRunnable
    method run (line 12) | public void run()

FILE: csharp/demo/demo20a03-semaphore-deadlock.cs
  class Demo20A03 (line 10) | class Demo20A03 : IRunnable
    method run (line 12) | public void run()

FILE: csharp/demo/demo20b-semaphore.cs
  class Demo20B (line 10) | class Demo20B : IRunnable
    method run (line 12) | public void run()

FILE: csharp/demo/demo21a01-condition-variable.cs
  class Demo21A01 (line 16) | class Demo21A01 : IRunnable
    method run (line 18) | public void run()

FILE: csharp/demo/demo21a02-condition-variable.cs
  class Demo21A02 (line 9) | class Demo21A02 : IRunnable
    method run (line 11) | public void run()

FILE: csharp/demo/demo21a03-condition-variable.cs
  class Demo21A03 (line 9) | class Demo21A03 : IRunnable
    method run (line 11) | public void run()

FILE: csharp/demo/demo21b-condition-variable.cs
  class Demo21B (line 9) | class Demo21B : IRunnable
    method run (line 11) | public void run()
    method foo (line 18) | private void foo()
    method egg (line 38) | private void egg()
    class Global (line 63) | private class Global

FILE: csharp/demo/demo22a-blocking-queue.cs
  class Demo22A (line 11) | class Demo22A : IRunnable
    method run (line 13) | public void run()
    method producer (line 25) | private void producer(BlockingCollection<string> queue)
    method consumer (line 38) | private void consumer(BlockingCollection<string> queue)

FILE: csharp/demo/demo22b-blocking-queue.cs
  class Demo22B (line 11) | class Demo22B : IRunnable
    method run (line 13) | public void run()
    method producer (line 25) | private void producer(BlockingCollection<string> queue)
    method consumer (line 39) | private void consumer(BlockingCollection<string> queue)

FILE: csharp/demo/demo23a01-thread-local.cs
  class Demo23A01 (line 10) | class Demo23A01 : IRunnable
    method run (line 12) | public void run()
    class MyTask (line 27) | class MyTask
      method get (line 31) | public static string get()
      method set (line 41) | public static void set(string value)

FILE: csharp/demo/demo23a02-thread-local.cs
  class Demo23A02 (line 12) | class Demo23A02 : IRunnable
    method run (line 14) | public void run()
    class MyTask (line 29) | class MyTask
      method get (line 33) | public static string get()
      method set (line 38) | public static void set(string value)

FILE: csharp/demo/demo23b-thread-local.cs
  class Demo23B (line 11) | class Demo23B : IRunnable
    method run (line 13) | public void run()
    class Counter (line 44) | class Counter
    class MyTask (line 50) | class MyTask
      method getCounter (line 54) | public static int getCounter()
      method increaseCounter (line 59) | public static void increaseCounter()

FILE: csharp/demo/demo24-volatile.cs
  class Demo24 (line 9) | class Demo24 : IRunnable
    method run (line 11) | public void run()
    method doTask (line 21) | private void doTask()
    class Global (line 31) | class Global

FILE: csharp/demo/demo25a-atomic.cs
  class Demo25A (line 10) | class Demo25A : IRunnable
    method run (line 12) | public void run()
    class Global (line 36) | class Global

FILE: csharp/demo/demo25b-atomic.cs
  class Demo25B (line 10) | class Demo25B : IRunnable
    method run (line 12) | public void run()
    class Global (line 36) | class Global

FILE: csharp/demoex/demoex-async-future-a01.cs
  class DemoExAsyncA01 (line 10) | class DemoExAsyncA01 : IRunnable
    method run (line 12) | public async void run()
    method doSomething (line 23) | private async Task doSomething(string taskName)

FILE: csharp/demoex/demoex-async-future-a02.cs
  class DemoExAsyncA02 (line 10) | class DemoExAsyncA02 : IRunnable
    method run (line 12) | public async void run()
    method getSquared (line 27) | private async Task<int> getSquared(int x)

FILE: csharp/demoex/demoex-async-future-a03.cs
  class DemoExAsyncA03 (line 10) | class DemoExAsyncA03 : IRunnable
    method run (line 12) | public async void run()
    method getSquared (line 23) | private async Task<int> getSquared(int x)

FILE: csharp/demoex/demoex-async-future-a04.cs
  class DemoExAsyncA04 (line 9) | class DemoExAsyncA04 : IRunnable
    method run (line 11) | public async void run()
    method cookEggs (line 22) | private async Task<string> cookEggs()

FILE: csharp/demoex/demoex-async-future-a05.cs
  class DemoExAsyncA05 (line 9) | class DemoExAsyncA05 : IRunnable
    method run (line 11) | public void run()
    method cookEggs (line 26) | private async Task<string> cookEggs()

FILE: csharp/demoex/demoex-async-future-b01.cs
  class DemoExAsyncB01 (line 12) | class DemoExAsyncB01 : IRunnable
    method run (line 14) | public void run()
    method doAction (line 33) | private async Task doAction(string actionName)

FILE: csharp/demoex/demoex-async-future-b02.cs
  class DemoExAsyncB02 (line 12) | class DemoExAsyncB02 : IRunnable
    method run (line 14) | public void run()
    method doAction (line 34) | private async Task doAction(string actionName)

FILE: csharp/demoex/demoex-async-future-b03.cs
  class DemoExAsyncB03 (line 9) | class DemoExAsyncB03 : IRunnable
    method run (line 11) | public void run()
    method cookEggs (line 25) | private async Task<string> cookEggs()
    method makeCoffee (line 36) | private async Task<string> makeCoffee()

FILE: csharp/demoex/demoex-async-future-b04.cs
  class DemoExAsyncB04 (line 9) | class DemoExAsyncB04 : IRunnable
    method run (line 11) | public void run()
    method validate (line 23) | private async Task<bool> validate(string userName)
    method queryUserAge (line 36) | private async Task<int> queryUserAge(string userName)

FILE: csharp/demoex/demoex-async-future-c01.cs
  class DemoExAsyncC01 (line 9) | class DemoExAsyncC01 : IRunnable
    method run (line 11) | public void run()
    method getSquared (line 21) | private async Task<int> getSquared(int x)
    method getDiv2 (line 27) | private async Task<int> getDiv2(int x)

FILE: csharp/demoex/demoex-async-future-c02.cs
  class DemoExAsyncC02 (line 9) | class DemoExAsyncC02 : IRunnable
    method run (line 11) | public void run()
    method getSquared (line 21) | private async Task<int> getSquared(int x)
    method getDiv2 (line 27) | private async Task<int> getDiv2(int x)

FILE: csharp/exercise/exer01a-max-div.cs
  class Exer01A (line 8) | class Exer01A : IRunnable
    method run (line 10) | public void run()

FILE: csharp/exercise/exer01b-max-div.cs
  class Exer01B (line 11) | class Exer01B : IRunnable
    method run (line 13) | public void run()
    method prepareArg (line 81) | private List<WorkerArg> prepareArg(int rangeStart, int rangeEnd, int n...
    type WorkerArg (line 104) | readonly struct WorkerArg
      method WorkerArg (line 107) | public WorkerArg(int iStart, int iEnd) => (this.iStart, this.iEnd) =...
    type WorkerResult (line 111) | readonly struct WorkerResult
      method WorkerResult (line 114) | public WorkerResult(int value, int numDiv) => (this.value, this.numD...

FILE: csharp/exercise/exer01c-max-div.cs
  class Exer01C (line 10) | class Exer01C : IRunnable
    method run (line 12) | public void run()
    method prepareArg (line 65) | private List<WorkerArg> prepareArg(int rangeStart, int rangeEnd, int n...
    type WorkerArg (line 88) | readonly struct WorkerArg
      method WorkerArg (line 91) | public WorkerArg(int iStart, int iEnd) => (this.iStart, this.iEnd) =...
    class WorkerResult (line 95) | class WorkerResult
      method update (line 100) | public void update(int value, int numDiv)

FILE: csharp/exercise/exer02a01-producer-consumer.cs
  class Exer02A01 (line 13) | class Exer02A01 : IRunnable
    method run (line 15) | public void run()
    method producer (line 23) | private void producer(BlockingCollection<int> queue)
    method consumer (line 35) | private void consumer(BlockingCollection<int> queue)

FILE: csharp/exercise/exer02a02-producer-consumer.cs
  class Exer02A02 (line 13) | class Exer02A02 : IRunnable
    method run (line 15) | public void run()
    method producer (line 26) | private void producer(BlockingCollection<int> queue)
    method consumer (line 38) | private void consumer(BlockingCollection<int> queue)

FILE: csharp/exercise/exer02a03-producer-consumer.cs
  class Exer02A03 (line 13) | class Exer02A03 : IRunnable
    method run (line 15) | public void run()
    method producer (line 26) | private void producer(BlockingCollection<int> queue)
    method consumer (line 38) | private void consumer(string name, BlockingCollection<int> queue)

FILE: csharp/exercise/exer02a04-producer-consumer.cs
  class Exer02A04 (line 14) | class Exer02A04 : IRunnable
    method run (line 16) | public void run()
    method producer (line 42) | private void producer(BlockingCollection<int> queue, int startValue)
    method consumer (line 57) | private void consumer(BlockingCollection<int> queue)

FILE: csharp/exercise/exer02b01-producer-consumer.cs
  class Exer02B01 (line 13) | class Exer02B01 : IRunnable
    method run (line 15) | public void run()
    method producer (line 27) | private void producer(Semaphore semFill, Semaphore semEmpty, Queue<int...
    method consumer (line 43) | private void consumer(Semaphore semFill, Semaphore semEmpty, Queue<int...

FILE: csharp/exercise/exer02b02-producer-consumer.cs
  class Exer02B02 (line 13) | class Exer02B02 : IRunnable
    method run (line 15) | public void run()
    method producer (line 29) | private void producer(Semaphore semFill, Semaphore semEmpty,
    method consumer (line 46) | private void consumer(Semaphore semFill, Semaphore semEmpty, Queue<int...

FILE: csharp/exercise/exer02b03-producer-consumer.cs
  class Exer02B03 (line 13) | class Exer02B03 : IRunnable
    method run (line 15) | public void run()
    method producer (line 29) | private void producer(Semaphore semFill, Semaphore semEmpty,
    method consumer (line 43) | private void consumer(Semaphore semFill, Semaphore semEmpty, Queue<int...

FILE: csharp/exercise/exer02b04-producer-consumer.cs
  class Exer02B04 (line 13) | class Exer02B04 : IRunnable
    method run (line 15) | public void run()
    method producer (line 46) | private void producer(Semaphore semFill, Semaphore semEmpty,
    method consumer (line 60) | private void consumer(Semaphore semFill, Semaphore semEmpty, Queue<int...

FILE: csharp/exercise/exer02c-producer-consumer.cs
  class Exer02C (line 13) | class Exer02C : IRunnable
    method run (line 15) | public void run()
    method producer (line 49) | private void producer(ProdConsMonitor<int> monitor, int startValue)
    method consumer (line 60) | private void consumer(ProdConsMonitor<int> monitor)
    class ProdConsMonitor (line 71) | class ProdConsMonitor<T>
      method init (line 80) | public void init(int maxQueueSize, Queue<T> queue)
      method add (line 87) | public void add(T item)
      method remove (line 108) | public T remove()

FILE: csharp/exercise/exer03a-readers-writers.cs
  class Exer03A (line 11) | class Exer03A : IRunnable
    method run (line 13) | public void run()
    method doTaskWriter (line 33) | private static void doTaskWriter(int delayTime)
    method doTaskReader (line 47) | private void doTaskReader(int delayTime)
    class Global (line 75) | class Global

FILE: csharp/exercise/exer03b-readers-writers.cs
  class Exer03B (line 11) | class Exer03B : IRunnable
    method run (line 13) | public void run()
    method doTaskWriter (line 33) | private static void doTaskWriter(int delayTime)
    method doTaskReader (line 50) | private void doTaskReader(int delayTime)
    class Global (line 81) | class Global

FILE: csharp/exercise/exer04a-dining-philosophers.cs
  class Exer04A (line 10) | class Exer04A : IRunnable
    method run (line 12) | public void run()

FILE: csharp/exercise/exer04b-dining-philosophers.cs
  class Exer04B (line 10) | class Exer04B : IRunnable
    method run (line 12) | public void run()

FILE: csharp/exercise/exer05-util.cs
  class Exer05Util (line 5) | class Exer05Util
    method getScalarProduct (line 7) | public static double getScalarProduct(double[] u, double[] v)
    method getTransposeMatrix (line 19) | public static double[][] getTransposeMatrix(double[][] input)
    method printMatrix (line 34) | public static void printMatrix(double[][] mat)
    method create2dArray (line 46) | public static T[][] create2dArray<T>(int height, int width)

FILE: csharp/exercise/exer05a-product-matrix-vector.cs
  class Exer05A (line 10) | class Exer05A : IRunnable
    method run (line 12) | public void run()
    method getProduct (line 32) | private double[] getProduct(double[][] mat, double[] vec)

FILE: csharp/exercise/exer05b-product-matrix-matrix.cs
  class Exer05B (line 10) | class Exer05B : IRunnable
    method run (line 12) | public void run()
    method getProduct (line 31) | private double[][] getProduct(double[][] matA, double[][] matB)

FILE: csharp/exercise/exer06a-blocking-queue.cs
  class Exer06A (line 10) | class Exer06A : IRunnable
    method run (line 12) | public void run()
    method producer (line 20) | private void producer(MySynchronousQueue<string> queue)
    method consumer (line 33) | private void consumer(MySynchronousQueue<string> queue)
    class MySynchronousQueue (line 46) | class MySynchronousQueue<T>
      method put (line 53) | public void put(T value)
      method take (line 61) | public T take()

FILE: csharp/exercise/exer06b01-blocking-queue.cs
  class Exer06B01 (line 12) | class Exer06B01 : IRunnable
    method run (line 14) | public void run()
    method producer (line 22) | private void producer(MyBlockingQueue<string> queue)
    method consumer (line 35) | private void consumer(MyBlockingQueue<string> queue)
    class MyBlockingQueue (line 54) | class MyBlockingQueue<T>
      method MyBlockingQueue (line 63) | public MyBlockingQueue(int capacity)
      method put (line 76) | public void put(T value)
      method take (line 89) | public T take()

FILE: csharp/exercise/exer06b02-blocking-queue.cs
  class Exer06B02 (line 12) | class Exer06B02 : IRunnable
    method run (line 14) | public void run()
    method producer (line 22) | private void producer(MyBlockingQueue<string> queue)
    method consumer (line 34) | private void consumer(MyBlockingQueue<string> queue)
    class MyBlockingQueue (line 53) | class MyBlockingQueue<T>
      method MyBlockingQueue (line 62) | public MyBlockingQueue(int capacity)
      method put (line 72) | public void put(T value)
      method take (line 95) | public T take()

FILE: csharp/exercise/exer07a-data-server.cs
  class Exer07A (line 10) | class Exer07A : IRunnable
    method run (line 12) | public void run()
    class DataServer (line 19) | private class DataServer
      class Counter (line 21) | private class Counter
        method Counter (line 24) | public Counter(int value)
      method processRequest (line 31) | public void processRequest()
      method checkAuthUser (line 55) | private void checkAuthUser()
      method processFiles (line 65) | private void processFiles(String[] lstFileName, Counter counter)

FILE: csharp/exercise/exer07b-data-server.cs
  class Exer07B (line 10) | class Exer07B : IRunnable
    method run (line 12) | public void run()
    class DataServer (line 19) | private class DataServer
      method processRequest (line 21) | public void processRequest()
      method checkAuthUser (line 42) | private void checkAuthUser()
      method processFiles (line 52) | private void processFiles(String[] lstFileName, Semaphore sem)

FILE: csharp/exercise/exer07c-data-server.cs
  class Exer07C (line 10) | class Exer07C : IRunnable
    method run (line 12) | public void run()
    class DataServer (line 19) | private class DataServer
      method processRequest (line 21) | public void processRequest()
      method checkAuthUser (line 39) | private void checkAuthUser()
      method processFiles (line 49) | private void processFiles(String[] lstFileName, CountdownEvent latch)

FILE: csharp/exercise/exer07d-data-server.cs
  class Exer07D (line 11) | class Exer07D : IRunnable
    method run (line 13) | public void run()
    class DataServer (line 20) | private class DataServer
      method processRequest (line 22) | public void processRequest()
      method checkAuthUser (line 43) | private void checkAuthUser()
      method processFiles (line 53) | private void processFiles(String[] lstFileName, BlockingCollection<s...

FILE: csharp/exercise/exer08-exec-service-main.cs
  class MainApp (line 12) | class MainApp : IRunnable
    method run (line 14) | public void run()
  class MyTask (line 43) | class MyTask : IRunnable
    method MyTask (line 47) | public MyTask(char id) {
    method run (line 51) | public void run() {

FILE: csharp/exercise/exer08-exec-service-v0a.cs
  class MyExecServiceV0A (line 16) | class MyExecServiceV0A
    method MyExecServiceV0A (line 24) | public MyExecServiceV0A(int numThreads) {
    method init (line 30) | private void init(int inpNumThreads)
    method submit (line 42) | public void submit(IRunnable task)
    method waitTaskDone (line 49) | public void waitTaskDone()
    method shutdown (line 58) | public void shutdown()
    method threadWorkerFunc (line 68) | private static void threadWorkerFunc(MyExecServiceV0A thisPtr)

FILE: csharp/exercise/exer08-exec-service-v0b.cs
  class MyExecServiceV0B (line 17) | class MyExecServiceV0B
    class EmptyTask (line 27) | private class EmptyTask : IRunnable
      method run (line 29) | public void run() { }
    method MyExecServiceV0B (line 34) | public MyExecServiceV0B(int numThreads) {
    method init (line 40) | private void init(int inpNumThreads)
    method submit (line 54) | public void submit(IRunnable task)
    method waitTaskDone (line 61) | public void waitTaskDone()
    method shutdown (line 76) | public void shutdown()
    method threadWorkerFunc (line 96) | private static void threadWorkerFunc(MyExecServiceV0B thisPtr)

FILE: csharp/exercise/exer08-exec-service-v1a.cs
  class MyExecServiceV1A (line 15) | class MyExecServiceV1A
    method MyExecServiceV1A (line 27) | public MyExecServiceV1A(int numThreads) {
    method init (line 33) | private void init(int inpNumThreads)
    method submit (line 49) | public void submit(IRunnable task)
    method waitTaskDone (line 60) | public void waitTaskDone()
    method shutdown (line 84) | public void shutdown()
    method threadWorkerFunc (line 101) | private static void threadWorkerFunc(MyExecServiceV1A thisPtr)

FILE: csharp/exercise/exer08-exec-service-v1b.cs
  class MyExecServiceV1B (line 15) | class MyExecServiceV1B
    method MyExecServiceV1B (line 29) | public MyExecServiceV1B(int numThreads) {
    method init (line 35) | private void init(int inpNumThreads)
    method submit (line 51) | public void submit(IRunnable task)
    method waitTaskDone (line 62) | public void waitTaskDone()
    method shutdown (line 87) | public void shutdown()
    method threadWorkerFunc (line 104) | private static void threadWorkerFunc(MyExecServiceV1B thisPtr)

FILE: csharp/exercise/exer08-exec-service-v2a.cs
  class MyExecServiceV2A (line 15) | class MyExecServiceV2A
    method MyExecServiceV2A (line 29) | public MyExecServiceV2A(int numThreads) {
    method init (line 35) | private void init(int inpNumThreads)
    method submit (line 50) | public void submit(IRunnable task)
    method waitTaskDone (line 61) | public void waitTaskDone()
    method shutdown (line 82) | public void shutdown()
    method threadWorkerFunc (line 103) | private static void threadWorkerFunc(MyExecServiceV2A thisPtr)

FILE: csharp/exercise/exer08-exec-service-v2b.cs
  class MyExecServiceV2B (line 15) | class MyExecServiceV2B
    method MyExecServiceV2B (line 27) | public MyExecServiceV2B(int numThreads) {
    method init (line 33) | private void init(int inpNumThreads)
    method submit (line 48) | public void submit(IRunnable task)
    method waitTaskDone (line 59) | public void waitTaskDone()
    method shutdown (line 82) | public void shutdown()
    method threadWorkerFunc (line 100) | private static void threadWorkerFunc(MyExecServiceV2B thisPtr)

FILE: java/src/demo00_intro/App.java
  class App (line 10) | public class App {
    method main (line 12) | public static void main(String[] args) {
  class ExampleThread (line 25) | class ExampleThread extends Thread {
    method run (line 26) | @Override

FILE: java/src/demo01_hello/AppA01.java
  class AppA01 (line 10) | public class AppA01 {
    method main (line 12) | public static void main(String[] args) throws InterruptedException {
  class ExampleThread (line 22) | class ExampleThread extends Thread {
    method run (line 23) | @Override

FILE: java/src/demo01_hello/AppA02.java
  class AppA02 (line 10) | public class AppA02 {
    method main (line 12) | public static void main(String[] args) throws InterruptedException {

FILE: java/src/demo01_hello/AppB01.java
  class AppB01 (line 10) | public class AppB01 {
    method main (line 12) | public static void main(String[] args) throws InterruptedException {
  class ExampleRunnable (line 28) | class ExampleRunnable implements Runnable {
    method run (line 29) | @Override

FILE: java/src/demo01_hello/AppB02.java
  class AppB02 (line 10) | public class AppB02 {
    method main (line 12) | public static void main(String[] args) throws InterruptedException {

FILE: java/src/demo01_hello/AppB03.java
  class AppB03 (line 10) | public class AppB03 {
    method main (line 12) | public static void main(String[] args) throws InterruptedException {

FILE: java/src/demo01_hello/AppC01.java
  class AppC01 (line 10) | public class AppC01 {
    method main (line 12) | public static void main(String[] args) throws InterruptedException {
    method doTask (line 21) | private static void doTask() {

FILE: java/src/demo01_hello/AppC02.java
  class AppC02 (line 10) | public class AppC02 {
    method main (line 12) | public static void main(String[] args) throws InterruptedException {
    method doTask (line 21) | private static void doTask() {

FILE: java/src/demo01_hello/AppExtra.java
  class AppExtra (line 10) | public class AppExtra {
    method main (line 12) | public static void main(String[] args) throws InterruptedException {

FILE: java/src/demo02_join/AppA.java
  class AppA (line 9) | public class AppA {
    method main (line 11) | public static void main(String[] args) throws InterruptedException {
    method doHeavyTask (line 21) | @SuppressWarnings("unused")

FILE: java/src/demo02_join/AppB.java
  class AppB (line 9) | public class AppB {
    method main (line 11) | public static void main(String[] args) {

FILE: java/src/demo03_pass_arg/AppA.java
  class AppA (line 10) | public class AppA {
    method main (line 12) | public static void main(String[] args) throws InterruptedException {
  class MyThread (line 24) | class MyThread extends Thread {
    method MyThread (line 29) | public MyThread(int a, double b, String c) {
    method run (line 36) | @Override

FILE: java/src/demo03_pass_arg/AppB.java
  class AppB (line 10) | public class AppB {
    method main (line 12) | public static void main(String[] args) throws InterruptedException {
    method doTask (line 21) | private static void doTask(int a, double b, String c) {

FILE: java/src/demo03_pass_arg/AppC.java
  class AppC (line 12) | public class AppC {
    method main (line 14) | public static void main(String[] args) throws InterruptedException {

FILE: java/src/demo04_sleep/App.java
  class App (line 9) | public class App {
    method main (line 11) | public static void main(String[] args) throws InterruptedException {

FILE: java/src/demo05_id/App.java
  class App (line 9) | public class App {
    method main (line 11) | public static void main(String[] args) {

FILE: java/src/demo06_list_threads/AppA.java
  class AppA (line 12) | public class AppA {
    method main (line 14) | public static void main(String[] args) {

FILE: java/src/demo06_list_threads/AppB01.java
  class AppB01 (line 12) | public class AppB01 {
    method main (line 14) | public static void main(String[] args) {

FILE: java/src/demo06_list_threads/AppB02.java
  class AppB02 (line 12) | public class AppB02 {
    method main (line 14) | public static void main(String[] args) {

FILE: java/src/demo07_terminate/AppA.java
  class AppA (line 10) | public class AppA {
    method main (line 12) | public static void main(String[] args) throws InterruptedException {

FILE: java/src/demo07_terminate/AppB.java
  class AppB (line 14) | public class AppB {
    method main (line 16) | public static void main(String[] args) throws InterruptedException {

FILE: java/src/demo08_return_value/AppA.java
  class AppA (line 9) | public class AppA {
    method main (line 11) | public static void main(String[] args) throws InterruptedException {
  class MyThread (line 29) | class MyThread extends Thread {
    method MyThread (line 33) | public MyThread(int arg) {
    method run (line 38) | @Override

FILE: java/src/demo08_return_value/AppB.java
  class AppB (line 9) | public class AppB {
    method main (line 11) | public static void main(String[] args) throws InterruptedException {
    method doubleValue (line 29) | private static int doubleValue(int value) {

FILE: java/src/demo08_return_value/AppC.java
  class AppC (line 14) | public class AppC {
    method main (line 16) | public static void main(String[] args) throws InterruptedException, Ex...
  class SimpleCalculator (line 33) | class SimpleCalculator {
    method calculate (line 36) | public Future<Integer> calculate(Integer input) {
    method shutdown (line 43) | public void shutdown() {

FILE: java/src/demo09_detach/App.java
  class App (line 9) | public class App {
    method main (line 11) | public static void main(String[] args) throws InterruptedException {

FILE: java/src/demo10_yield/App.java
  class App (line 12) | public class App {
    method main (line 14) | public static void main(String[] args) {
    method littleSleep (line 25) | private static void littleSleep(int ns) {

FILE: java/src/demo11_exec_service/AppA.java
  class AppA (line 15) | public class AppA {
    method main (line 17) | public static void main(String[] args) {

FILE: java/src/demo11_exec_service/AppB01.java
  class AppB01 (line 14) | public class AppB01 {
    method main (line 16) | public static void main(String[] args) throws InterruptedException {

FILE: java/src/demo11_exec_service/AppB02.java
  class AppB02 (line 15) | public class AppB02 {
    method main (line 17) | public static void main(String[] args) throws InterruptedException {

FILE: java/src/demo11_exec_service/AppC01.java
  class AppC01 (line 19) | public class AppC01 {
    method main (line 21) | public static void main(String[] args) throws InterruptedException, Ex...

FILE: java/src/demo11_exec_service/AppC02.java
  class AppC02 (line 15) | public class AppC02 {
    method main (line 17) | public static void main(String[] args) throws InterruptedException, Ex...
    method getSquared (line 33) | private static int getSquared(int x) {

FILE: java/src/demo11_exec_service/AppC03.java
  class AppC03 (line 15) | public class AppC03 {
    method main (line 17) | public static void main(String[] args) throws InterruptedException, Ex...
    method getSquared (line 35) | private static int getSquared(int x) {

FILE: java/src/demo11_exec_service/AppC04.java
  class AppC04 (line 16) | public class AppC04 {
    method main (line 18) | public static void main(String[] args) throws InterruptedException, Ex...
    method getSquared (line 41) | private static int getSquared(int x) {

FILE: java/src/demo11_exec_service/AppC05.java
  class AppC05 (line 15) | public class AppC05 {
    method main (line 17) | public static void main(String[] args) throws InterruptedException, Ex...

FILE: java/src/demo11_exec_service/AppC06.java
  class AppC06 (line 16) | public class AppC06 {
    method main (line 18) | public static void main(String[] args) throws InterruptedException, Ex...
    method doTask (line 53) | private static String doTask(int number) {

FILE: java/src/demo11_exec_service/AppExtra.java
  class AppExtra (line 27) | public class AppExtra {
    method main (line 29) | public static void main(String[] args) {
  class TreeNode (line 49) | class TreeNode {
    method TreeNode (line 53) | TreeNode(int value, TreeNode... children) {
  class TreeSumTask (line 61) | class TreeSumTask extends RecursiveTask<Integer> {
    method TreeSumTask (line 66) | TreeSumTask(TreeNode node) {
    method compute (line 70) | @Override

FILE: java/src/demo12_race_condition/AppA.java
  class AppA (line 11) | public class AppA {
    method main (line 13) | public static void main(String[] args) {

FILE: java/src/demo12_race_condition/AppB01.java
  class AppB01 (line 12) | public class AppB01 {
    method main (line 14) | public static void main(String[] args) {
    method getResult (line 21) | private static int getResult(int N) {
    method countTrue (line 34) | private static int countTrue(boolean[] a, int N) {

FILE: java/src/demo12_race_condition/AppB02.java
  class AppB02 (line 12) | public class AppB02 {
    method main (line 14) | public static void main(String[] args) throws InterruptedException {
    method countTrue (line 44) | private static int countTrue(boolean[] a, int N) {

FILE: java/src/demo12_race_condition/AppC01.java
  class AppC01 (line 11) | public class AppC01 {
    method main (line 13) | public static void main(String[] args) throws InterruptedException {
    class Global (line 43) | private static class Global {

FILE: java/src/demo12_race_condition/AppC02.java
  class AppC02 (line 9) | public class AppC02 {
    method main (line 11) | public static void main(String[] args) throws InterruptedException {
    class Global (line 38) | private static class Global {

FILE: java/src/demo13_mutex/AppA.java
  class AppA (line 9) | public class AppA {
    method main (line 11) | public static void main(String[] args) {

FILE: java/src/demo13_mutex/AppB.java
  class AppB (line 15) | public class AppB {
    method main (line 17) | public static void main(String[] args) throws InterruptedException {
    class Global (line 53) | private static class Global {

FILE: java/src/demo14_synchronized_block/AppA.java
  class AppA (line 12) | public class AppA {
    method main (line 14) | public static void main(String[] args) throws InterruptedException {
    class MyTask (line 35) | private static class MyTask implements Runnable {
      method run (line 38) | @Override

FILE: java/src/demo14_synchronized_block/AppB01.java
  class AppB01 (line 12) | public class AppB01 {
    method main (line 14) | public static void main(String[] args) throws InterruptedException {
    class MyTask (line 35) | private static class MyTask implements Runnable {
      method run (line 38) | @Override

FILE: java/src/demo14_synchronized_block/AppB02.java
  class AppB02 (line 20) | public class AppB02 {
    method main (line 22) | public static void main(String[] args) throws InterruptedException {
    class Worker (line 41) | private static class Worker extends Thread {
      method run (line 44) | @Override

FILE: java/src/demo14_synchronized_block/AppC.java
  class AppC (line 12) | public class AppC {
    method main (line 14) | public static void main(String[] args) throws InterruptedException {
    class Worker (line 33) | private static class Worker extends Thread {
      method run (line 36) | @Override
      method incCounter (line 41) | private static synchronized void incCounter() {

FILE: java/src/demo15_deadlock/AppA.java
  class AppA (line 12) | public class AppA {
    method main (line 14) | public static void main(String[] args) throws InterruptedException {
    method doTask (line 30) | private static void doTask(Semaphore mutex, String name) {

FILE: java/src/demo15_deadlock/AppB.java
  class AppB (line 10) | public class AppB {
    method main (line 12) | public static void main(String[] args) throws InterruptedException {

FILE: java/src/demo16_monitor/App.java
  class App (line 12) | public class App {
    method main (line 14) | public static void main(String[] args) throws InterruptedException {
  class Counter (line 46) | class Counter {
  class MyMonitor (line 52) | class MyMonitor {
    method init (line 55) | public void init(Counter counter) {
    method increaseCounter (line 59) | public void increaseCounter() {

FILE: java/src/demo17_reentrant_lock/AppA01.java
  class AppA01 (line 13) | public class AppA01 {
    method main (line 15) | public static void main(String[] args) {

FILE: java/src/demo17_reentrant_lock/AppA02.java
  class AppA02 (line 14) | public class AppA02 {
    method main (line 16) | public static void main(String[] args) {
    class Worker (line 24) | private static class Worker extends Thread {
      method Worker (line 29) | public Worker(char name) {
      method run (line 33) | @Override

FILE: java/src/demo17_reentrant_lock/AppB01.java
  class AppB01 (line 14) | public class AppB01 {
    method main (line 16) | public static void main(String[] args) {

FILE: java/src/demo17_reentrant_lock/AppB02.java
  class AppB02 (line 12) | public class AppB02 {
    method main (line 14) | public static void main(String[] args) throws InterruptedException {
    class Worker (line 22) | private static class Worker extends Thread {
      method Worker (line 27) | public Worker(char name) {
      method run (line 31) | @Override

FILE: java/src/demo18_barrier_latch/AppA01.java
  class AppA01 (line 14) | public class AppA01 {
    method main (line 16) | public static void main(String[] args) {

FILE: java/src/demo18_barrier_latch/AppA02.java
  class AppA02 (line 14) | public class AppA02 {
    method main (line 16) | public static void main(String[] args) {

FILE: java/src/demo18_barrier_latch/AppA03.java
  class AppA03 (line 14) | public class AppA03 {
    method main (line 16) | public static void main(String[] args) {

FILE: java/src/demo18_barrier_latch/AppB01.java
  class AppB01 (line 17) | public class AppB01 {
    method main (line 19) | public static void main(String[] args) {

FILE: java/src/demo18_barrier_latch/AppB02.java
  class AppB02 (line 15) | public class AppB02 {
    method main (line 17) | public static void main(String[] args) throws InterruptedException {

FILE: java/src/demo19_read_write_lock/App.java
  class App (line 15) | public class App {
    method main (line 17) | public static void main(String[] args) {
  class Resource (line 67) | class Resource {

FILE: java/src/demo20_semaphore/AppA01.java
  class AppA01 (line 12) | public class AppA01 {
    method main (line 14) | public static void main(String[] args) {

FILE: java/src/demo20_semaphore/AppA02.java
  class AppA02 (line 12) | public class AppA02 {
    method main (line 14) | public static void main(String[] args) {

FILE: java/src/demo20_semaphore/AppA03.java
  class AppA03 (line 12) | public class AppA03 {
    method main (line 14) | public static void main(String[] args) {

FILE: java/src/demo20_semaphore/AppB.java
  class AppB (line 12) | public class AppB {
    method main (line 14) | public static void main(String[] args) {

FILE: java/src/demo21_condition_variable/AppA01.java
  class AppA01 (line 9) | public class AppA01 {
    method main (line 11) | public static void main(String[] args) {

FILE: java/src/demo21_condition_variable/AppA02.java
  class AppA02 (line 9) | public class AppA02 {
    method main (line 11) | public static void main(String[] args) {

FILE: java/src/demo21_condition_variable/AppA03.java
  class AppA03 (line 9) | public class AppA03 {
    method main (line 11) | public static void main(String[] args) {

FILE: java/src/demo21_condition_variable/AppB.java
  class AppB (line 9) | public class AppB {
    method main (line 11) | public static void main(String[] args) {
  class Global (line 20) | class Global {
  class FooThread (line 33) | class FooThread extends Thread {
    method run (line 34) | @Override
  class EggThread (line 59) | class EggThread extends Thread {
    method run (line 60) | @Override

FILE: java/src/demo22_blocking_queue/AppA.java
  class AppA (line 13) | public class AppA {
    method main (line 15) | public static void main(String[] args) {
    method producer (line 26) | private static void producer(BlockingQueue<String> queue) {
    method consumer (line 43) | private static void consumer(BlockingQueue<String> queue) {

FILE: java/src/demo22_blocking_queue/AppB.java
  class AppB (line 13) | public class AppB {
    method main (line 15) | public static void main(String[] args) {
    method producer (line 24) | private static void producer(BlockingQueue<String> queue) {
    method consumer (line 42) | private static void consumer(BlockingQueue<String> queue) {

FILE: java/src/demo22_blocking_queue/AppExtra.java
  class AppExtra (line 17) | public class AppExtra {
    method main (line 19) | public static void main(String[] args) {
    method producer (line 26) | private static void producer(BlockingQueue<String> queue) {
    method consumer (line 38) | private static void consumer(BlockingQueue<String> queue) {

FILE: java/src/demo23_thread_local/AppA01.java
  class AppA01 (line 10) | public class AppA01 {
    method main (line 12) | public static void main(String[] args) {
    class MyTask (line 27) | private static class MyTask {
      method get (line 30) | public static String get() {
      method set (line 39) | public static void set(String value) {

FILE: java/src/demo23_thread_local/AppA02.java
  class AppA02 (line 12) | public class AppA02 {
    method main (line 14) | public static void main(String[] args) {
    class MyTask (line 29) | private static class MyTask {
      method get (line 33) | public static String get() {
      method set (line 37) | public static void set(String value) {

FILE: java/src/demo23_thread_local/AppB.java
  class AppB (line 12) | public class AppB {
    method main (line 14) | public static void main(String[] args) throws InterruptedException {
    class Counter (line 41) | private static class Counter {
    class MyTask (line 47) | private static class MyTask {
      method getCounter (line 51) | public static int getCounter() {
      method increaseCounter (line 55) | public static void increaseCounter() {

FILE: java/src/demo24_volatile/App.java
  class App (line 9) | public class App {
    method main (line 11) | public static void main(String[] args) throws InterruptedException {
    method doTask (line 20) | private static void doTask() {
    class Global (line 29) | private static class Global {

FILE: java/src/demo25_atomic/AppA.java
  class AppA (line 11) | public class AppA {
    method main (line 13) | public static void main(String[] args) throws InterruptedException {
    class Global (line 36) | private static class Global {

FILE: java/src/demo25_atomic/AppB.java
  class AppB (line 12) | public class AppB {
    method main (line 14) | public static void main(String[] args) throws InterruptedException {
    class Global (line 38) | private static class Global {

FILE: java/src/demoex/async/AppA.java
  class AppA (line 9) | public class AppA {
    method main (line 11) | public static void main(String[] args) {

FILE: java/src/demoex/async/AppB01.java
  class AppB01 (line 19) | public class AppB01 {
    method main (line 21) | public static void main(String[] args) throws InterruptedException, Ex...
    method doAction (line 44) | private static Void doAction(String actionName) {

FILE: java/src/demoex/async/AppB02.java
  class AppB02 (line 19) | public class AppB02 {
    method main (line 21) | public static void main(String[] args) throws InterruptedException, Ex...
    method doAction (line 44) | private static Void doAction(String actionName) {

FILE: java/src/demoex/async/AppB03.java
  class AppB03 (line 14) | public class AppB03 {
    method main (line 16) | public static void main(String[] args) throws InterruptedException, Ex...
    method cookEggs (line 33) | private static String cookEggs() {
    method makeCoffee (line 47) | private static String makeCoffee() {

FILE: java/src/demoex/async/AppB04.java
  class AppB04 (line 14) | public class AppB04 {
    method main (line 19) | public static void main(String[] args) throws InterruptedException, Ex...
    method validate (line 33) | private static boolean validate(String userName) throws InterruptedExc...
    method queryUserAge (line 50) | private static int queryUserAge(String userName) {

FILE: java/src/demoex/async/AppC01.java
  class AppC01 (line 18) | public class AppC01 {
    method main (line 20) | public static void main(String[] args) throws InterruptedException, Ex...
    method getSquared (line 32) | private static int getSquared(int x) {
    method getDiv2 (line 37) | private static int getDiv2(int x) {

FILE: java/src/demoex/async/AppC02.java
  class AppC02 (line 12) | public class AppC02 {
    method main (line 14) | public static void main(String[] args) throws InterruptedException, Ex...
    method getSquared (line 26) | private static int getSquared(int x) {
    method getDiv2 (line 31) | private static int getDiv2(int x) {

FILE: java/src/exer01_max_div/AppA.java
  class AppA (line 12) | public class AppA {
    method main (line 14) | public static void main(String[] args) {

FILE: java/src/exer01_max_div/AppB.java
  class AppB (line 14) | public class AppB {
    method main (line 16) | public static void main(String[] args) throws InterruptedException {
    method prepareArg (line 81) | private static List<WorkerArg> prepareArg(int rangeStart, int rangeEnd...

FILE: java/src/exer01_max_div/AppC.java
  class AppC (line 14) | public class AppC {
    method main (line 16) | public static void main(String[] args) throws InterruptedException {
    method prepareArg (line 68) | private static List<WorkerArg> prepareArg(int rangeStart, int rangeEnd...
    class WorkerResult (line 94) | private static class WorkerResult {
      method update (line 98) | public void update(int value, int numDiv) {

FILE: java/src/exer02_producer_consumer/AppA01.java
  class AppA01 (line 15) | public class AppA01 {
    method main (line 17) | public static void main(String[] args) {
    method producer (line 24) | private static void producer(BlockingQueue<Integer> queue) {
    method consumer (line 39) | private static void consumer(BlockingQueue<Integer> queue) {

FILE: java/src/exer02_producer_consumer/AppA02.java
  class AppA02 (line 15) | public class AppA02 {
    method main (line 17) | public static void main(String[] args) {
    method producer (line 27) | private static void producer(BlockingQueue<Integer> queue) {
    method consumer (line 42) | private static void consumer(BlockingQueue<Integer> queue) {

FILE: java/src/exer02_producer_consumer/AppA03.java
  class AppA03 (line 15) | public class AppA03 {
    method main (line 17) | public static void main(String[] args) {
    method producer (line 27) | private static void producer(BlockingQueue<Integer> queue) {
    method consumer (line 42) | private static void consumer(String name, BlockingQueue<Integer> queue) {

FILE: java/src/exer02_producer_consumer/AppA04.java
  class AppA04 (line 16) | public class AppA04 {
    method main (line 18) | public static void main(String[] args) {
    method producer (line 36) | private static void producer(BlockingQueue<Integer> queue, int startVa...
    method consumer (line 50) | private static void consumer(BlockingQueue<Integer> queue) {

FILE: java/src/exer02_producer_consumer/AppB01.java
  class AppB01 (line 16) | public class AppB01 {
    method main (line 18) | public static void main(String[] args) {
    method producer (line 29) | private static void producer(Semaphore semFill, Semaphore semEmpty, Qu...
    method consumer (line 48) | private static void consumer(Semaphore semFill, Semaphore semEmpty, Qu...

FILE: java/src/exer02_producer_consumer/AppB02.java
  class AppB02 (line 16) | public class AppB02 {
    method main (line 18) | public static void main(String[] args) {
    method producer (line 31) | private static void producer(Semaphore semFill, Semaphore semEmpty,
    method consumer (line 51) | private static void consumer(Semaphore semFill, Semaphore semEmpty, Qu...

FILE: java/src/exer02_producer_consumer/AppB03.java
  class AppB03 (line 16) | public class AppB03 {
    method main (line 18) | public static void main(String[] args) {
    method producer (line 31) | private static void producer(Semaphore semFill, Semaphore semEmpty,
    method consumer (line 48) | private static void consumer(Semaphore semFill, Semaphore semEmpty, Qu...

FILE: java/src/exer02_producer_consumer/AppB04.java
  class AppB04 (line 17) | public class AppB04 {
    method main (line 19) | public static void main(String[] args) {
    method producer (line 40) | private static void producer(Semaphore semFill, Semaphore semEmpty,
    method consumer (line 57) | private static void consumer(Semaphore semFill, Semaphore semEmpty, Qu...

FILE: java/src/exer02_producer_consumer/AppC.java
  class AppC (line 16) | public class AppC {
    method main (line 18) | public static void main(String[] args) {
    method producer (line 41) | private static void producer(ProdConsMonitor<Integer> monitor, int sta...
    method consumer (line 55) | private static void consumer(ProdConsMonitor<Integer> monitor) {
  class ProdConsMonitor (line 72) | class ProdConsMonitor<T> {
    method init (line 80) | public void init(int maxQueueSize, Queue<T> queue) {
    method add (line 86) | public void add(T item) throws InterruptedException {
    method remove (line 105) | public T remove() throws InterruptedException {

FILE: java/src/exer03_readers_writers/AppA.java
  class AppA (line 14) | public class AppA {
    method main (line 16) | public static void main(String[] args) {
    method doTaskWriter (line 49) | private static void doTaskWriter(int delayTime) throws InterruptedExce...
    method doTaskReader (line 62) | private static void doTaskReader(int delayTime) throws InterruptedExce...
    class Global (line 88) | private static class Global {

FILE: java/src/exer03_readers_writers/AppB.java
  class AppB (line 14) | public class AppB {
    method main (line 16) | public static void main(String[] args) {
    method doTaskWriter (line 49) | private static void doTaskWriter(int delayTime) throws InterruptedExce...
    method doTaskReader (line 64) | private static void doTaskReader(int delayTime) throws InterruptedExce...
    class Global (line 92) | private static class Global {

FILE: java/src/exer04_dining_philosophers/AppA.java
  class AppA (line 12) | public class AppA {
    method main (line 14) | public static void main(String[] args) {

FILE: java/src/exer04_dining_philosophers/AppB.java
  class AppB (line 11) | public class AppB {
    method main (line 13) | public static void main(String[] args) {

FILE: java/src/exer05_product_matrix/AppA.java
  class AppA (line 12) | public class AppA {
    method main (line 14) | public static void main(String[] args) throws InterruptedException {
    method getProduct (line 33) | private static double[] getProduct(double[][] mat, double[] vec) throw...

FILE: java/src/exer05_product_matrix/AppB.java
  class AppB (line 12) | public class AppB {
    method main (line 14) | public static void main(String[] args) throws InterruptedException {
    method getProduct (line 32) | private static double[][] getProduct(double[][] matA, double[][] matB)...

FILE: java/src/exer05_product_matrix/MyUtil.java
  class MyUtil (line 7) | public class MyUtil {
    method getScalarProduct (line 18) | public static double getScalarProduct(double[] u, double[] v) {
    method getTransposeMatrix (line 30) | public static double[][] getTransposeMatrix(double[][] input) {
    method printMatrix (line 46) | public static void printMatrix(double[][] mat) {

FILE: java/src/exer06_blocking_queue/AppA.java
  class AppA (line 12) | public class AppA {
    method main (line 14) | public static void main(String[] args) {
    method producer (line 21) | private static void producer(MySynchronousQueue<String> queue) {
    method consumer (line 37) | private static void consumer(MySynchronousQueue<String> queue) {
    class MySynchronousQueue (line 55) | private static class MySynchronousQueue<T> {
      method put (line 61) | public void put(T value) throws InterruptedException {
      method take (line 68) | public T take() throws InterruptedException {

FILE: java/src/exer06_blocking_queue/AppB01.java
  class AppB01 (line 15) | public class AppB01 {
    method main (line 17) | public static void main(String[] args) {
    method producer (line 24) | private static void producer(MyBlockingQueue<String> queue) {
    method consumer (line 40) | private static void consumer(MyBlockingQueue<String> queue) {
    class MyBlockingQueue (line 63) | private static class MyBlockingQueue<T> {
      method MyBlockingQueue (line 71) | public MyBlockingQueue(int capacity) {
      method put (line 84) | public void put(T value) throws InterruptedException {
      method take (line 95) | public T take() throws InterruptedException {

FILE: java/src/exer06_blocking_queue/AppB02.java
  class AppB02 (line 14) | public class AppB02 {
    method main (line 16) | public static void main(String[] args) {
    method producer (line 23) | private static void producer(MyBlockingQueue<String> queue) {
    method consumer (line 39) | private static void consumer(MyBlockingQueue<String> queue) {
    class MyBlockingQueue (line 62) | private static class MyBlockingQueue<T> {
      method MyBlockingQueue (line 70) | public MyBlockingQueue(int capacity) {
      method put (line 79) | public void put(T value) throws InterruptedException {
      method take (line 97) | public T take() throws InterruptedException {

FILE: java/src/exer07_data_server/AppA.java
  class AppA (line 10) | public class AppA {
    method main (line 12) | public static void main(String[] args) throws InterruptedException {
    class DataServer (line 18) | private static class DataServer {
      class Counter (line 19) | private class Counter {
        method Counter (line 21) | public Counter(int value) {
      method processRequest (line 27) | public void processRequest() throws InterruptedException {
      method checkAuthUser (line 48) | private void checkAuthUser() {
      method processFiles (line 57) | private void processFiles(String[] lstFileName, Counter counter) {
      method sleepNoEx (line 76) | private static void sleepNoEx(long seconds) {

FILE: java/src/exer07_data_server/AppB.java
  class AppB (line 12) | public class AppB {
    method main (line 14) | public static void main(String[] args) throws InterruptedException {
    class DataServer (line 20) | private static class DataServer {
      method processRequest (line 21) | public void processRequest() throws InterruptedException {
      method checkAuthUser (line 40) | private void checkAuthUser() {
      method processFiles (line 49) | private void processFiles(String[] lstFileName, Semaphore sem) {
      method sleepNoEx (line 65) | private static void sleepNoEx(long seconds) {

FILE: java/src/exer07_data_server/AppC.java
  class AppC (line 12) | public class AppC {
    method main (line 14) | public static void main(String[] args) throws InterruptedException {
    class DataServer (line 20) | private static class DataServer {
      method processRequest (line 21) | public void processRequest() throws InterruptedException {
      method checkAuthUser (line 39) | private void checkAuthUser() {
      method processFiles (line 48) | private void processFiles(String[] lstFileName, CountDownLatch latch) {
      method sleepNoEx (line 64) | private static void sleepNoEx(long seconds) {

FILE: java/src/exer07_data_server/AppD.java
  class AppD (line 13) | public class AppD {
    method main (line 15) | public static void main(String[] args) throws InterruptedException {
    class DataServer (line 21) | private static class DataServer {
      method processRequest (line 22) | public void processRequest() throws InterruptedException {
      method checkAuthUser (line 41) | private void checkAuthUser() {
      method processFiles (line 50) | private void processFiles(String[] lstFileName, BlockingQueue<String...
      method sleepNoEx (line 70) | private static void sleepNoEx(long seconds) {

FILE: java/src/exer08_exec_service/App.java
  class App (line 11) | public class App {
    method main (line 13) | public static void main(String[] args) throws InterruptedException {
    class MyTask (line 40) | private static class MyTask implements Runnable {
      method MyTask (line 43) | public MyTask(char id) {
      method run (line 47) | @Override

FILE: java/src/exer08_exec_service/MyExecServiceV0A.java
  class MyExecServiceV0A (line 18) | public final class MyExecServiceV0A {
    method MyExecServiceV0A (line 26) | public MyExecServiceV0A(int numThreads) {
    method init (line 32) | private void init(int inpNumThreads) {
    method submit (line 44) | public void submit(Runnable task) {
    method waitTaskDone (line 50) | public void waitTaskDone() {
    method shutdown (line 62) | public void shutdown() {
    method threadWorkerFunc (line 71) | private static void threadWorkerFunc(MyExecServiceV0A thisPtr) {

FILE: java/src/exer08_exec_service/MyExecServiceV0B.java
  class MyExecServiceV0B (line 20) | public final class MyExecServiceV0B {
    method MyExecServiceV0B (line 34) | public MyExecServiceV0B(int numThreads) {
    method init (line 40) | private void init(int inpNumThreads) {
    method submit (line 54) | public void submit(Runnable task) {
    method waitTaskDone (line 60) | public void waitTaskDone() {
    method shutdown (line 76) | public void shutdown() {
    method threadWorkerFunc (line 100) | private static void threadWorkerFunc(MyExecServiceV0B thisPtr) {

FILE: java/src/exer08_exec_service/MyExecServiceV1A.java
  class MyExecServiceV1A (line 18) | public final class MyExecServiceV1A {
    method MyExecServiceV1A (line 30) | public MyExecServiceV1A(int numThreads) {
    method init (line 36) | private void init(int inpNumThreads) {
    method submit (line 52) | public void submit(Runnable task) {
    method waitTaskDone (line 61) | public void waitTaskDone() {
    method shutdown (line 86) | public void shutdown() {
    method threadWorkerFunc (line 108) | private static void threadWorkerFunc(MyExecServiceV1A thisPtr) {

FILE: java/src/exer08_exec_service/MyExecServiceV1B.java
  class MyExecServiceV1B (line 17) | public final class MyExecServiceV1B {
    method MyExecServiceV1B (line 31) | public MyExecServiceV1B(int numThreads) {
    method init (line 37) | private void init(int inpNumThreads) {
    method submit (line 53) | public void submit(Runnable task) {
    method waitTaskDone (line 62) | public void waitTaskDone() {
    method shutdown (line 86) | public void shutdown() {
    method threadWorkerFunc (line 108) | private static void threadWorkerFunc(MyExecServiceV1B thisPtr) {

FILE: java/src/exer08_exec_service/MyExecServiceV2A.java
  class MyExecServiceV2A (line 18) | public final class MyExecServiceV2A {
    method MyExecServiceV2A (line 32) | public MyExecServiceV2A(int numThreads) {
    method init (line 38) | private void init(int inpNumThreads) {
    method submit (line 53) | public void submit(Runnable task) {
    method waitTaskDone (line 62) | public void waitTaskDone() {
    method shutdown (line 84) | public void shutdown() {
    method threadWorkerFunc (line 109) | private static void threadWorkerFunc(MyExecServiceV2A thisPtr) {

FILE: java/src/exer08_exec_service/MyExecServiceV2B.java
  class MyExecServiceV2B (line 17) | public final class MyExecServiceV2B {
    method MyExecServiceV2B (line 29) | public MyExecServiceV2B(int numThreads) {
    method init (line 35) | private void init(int inpNumThreads) {
    method submit (line 50) | public void submit(Runnable task) {
    method waitTaskDone (line 80) | public void waitTaskDone() {
    method shutdown (line 103) | public void shutdown() {
    method threadWorkerFunc (line 126) | private static void threadWorkerFunc(MyExecServiceV2B thisPtr) {

FILE: js-nodejs/exerex-userhash-problem.js
  constant PORT (line 34) | const PORT = 8081;

FILE: js-nodejs/mylib_mutex.js
  class Mutex (line 17) | class Mutex {
    method constructor (line 23) | constructor(sharedArrayBuffer) {
    method getSAB (line 34) | getSAB() {
    method #requireValidStateSAB (line 39) | static #requireValidStateSAB(sharedArrayBuffer) {
    method #requireValidStateSA (line 52) | static #requireValidStateSA(sharedArray) {
    method #requireValidState (line 67) | #requireValidState() {
    method acquire (line 72) | acquire() {
    method release (line 92) | release() {
    method runExclusive (line 102) | runExclusive(callbackFunc) {

FILE: old/cpppthread-reentrant-lock-a.cpp
  function getFactorial (line 18) | int getFactorial(int n) {
  function main (line 46) | int main() {

FILE: old/cpppthread-reentrant-lock-b.cpp
  function getFactorial (line 16) | int getFactorial(int n) {
  function main (line 44) | int main() {

FILE: old/cppstd-data-race.cpp
  function writeToFile (line 10) | void writeToFile(string fileName, string programName) {
  function main (line 24) | int main(int argc, char* argv[]) {

FILE: old/cppstd-reentrant-lock-a.cpp
  function getFactorial (line 19) | int getFactorial(int n) {
  function routine (line 34) | void routine(int n) {
  function main (line 41) | int main() {

FILE: old/cppstd-reentrant-lock-b.cpp
  function getFactorial (line 17) | int getFactorial(int n) {
  function routine (line 32) | void routine(int n) {
  function main (line 39) | int main() {

FILE: python/demo00.py
  function do_task (line 10) | def do_task():

FILE: python/demo01_hello.py
  function do_task (line 9) | def do_task():

FILE: python/demo01ex_name.py
  function do_task (line 10) | def do_task():

FILE: python/demo02a_join.py
  function do_heavy_task (line 9) | def do_heavy_task():

FILE: python/demo03a_pass_arg.py
  function do_task (line 10) | def do_task(a: int, b: float, c: str):

FILE: python/demo03b_pass_arg.py
  function do_task (line 10) | def do_task(a: int, b: float, c: str):

FILE: python/demo04_sleep.py
  function do_task (line 10) | def do_task():

FILE: python/demo05_id.py
  function do_task (line 10) | def do_task():

FILE: python/demo06_list_threads.py
  function do_task (line 10) | def do_task(index):

FILE: python/demo07_terminate.py
  function do_task (line 15) | def do_task():

FILE: python/demo08a_return_value.py
  function double_value (line 9) | def double_value(value):

FILE: python/demo08b_return_value.py
  function double_value (line 9) | def double_value(result: dict, name: str, value):

FILE: python/demo09_detach.py
  function do_task (line 10) | def do_task():

FILE: python/demo11a_exec_service.py
  function do_task (line 10) | def do_task():

FILE: python/demo11b_exec_service.py
  function do_task (line 11) | def do_task(name: str):

FILE: python/demo11c01_exec_service.py
  function get_squared (line 10) | def get_squared(x):

FILE: python/demo11c02_exec_service.py
  function get_squared (line 11) | def get_squared(x):

FILE: python/demo12a_race_condition.py
  function do_task (line 10) | def do_task(index: int):

FILE: python/demo12b01_data_race_single.py
  function get_result (line 8) | def get_result(n: int):

FILE: python/demo12b02_data_race_multi.py
  function count_div_2 (line 10) | def count_div_2(a: list, n: int):
  function count_div_3 (line 16) | def count_div_3(a: list, n: int):

FILE: python/demo12c01_race_cond_data_race.py
  function do_task (line 14) | def do_task():

FILE: python/demo12c02_race_cond_data_race.py
  function do_task_a (line 14) | def do_task_a():
  function do_task_b (line 25) | def do_task_b():

FILE: python/demo13a_mutex.py
  function do_task (line 16) | def do_task():

FILE: python/demo14_synchronized_block.py
  function do_task (line 15) | def do_task():

FILE: python/demo15a_deadlock.py
  function do_task (line 14) | def do_task(name: str):

FILE: python/demo15b_deadlock.py
  function foo (line 16) | def foo():
  function bar (line 25) | def bar():

FILE: python/demo16_monitor.py
  class Monitor (line 11) | class Monitor:
    method __init__ (line 12) | def __init__(self, res: dict, field_name: str):
    method increase_counter (line 17) | def increase_counter(self):
  function do_task (line 25) | def do_task(mon: Monitor):

FILE: python/demo17a_reentrant_lock.py
  function do_task (line 14) | def do_task():

FILE: python/demo17b_reentrant_lock.py
  function do_task (line 14) | def do_task():

FILE: python/demo17c_reentrant_lock.py
  function do_task (line 15) | def do_task(name: str):

FILE: python/demo18a01_barrier.py
  function process_request (line 15) | def process_request(user_name: str, wait_time: int):

FILE: python/demo18a02_barrier.py
  function process_request (line 15) | def process_request(user_name: str, wait_time: int):

FILE: python/demo18a03_barrier.py
  function process_request (line 16) | def process_request(user_name: str, wait_time: int):

FILE: python/demo18b01_latch.py
  function process_request (line 15) | def process_request(user_name: str, wait_time: int):

FILE: python/demo18b02_latch.py
  function do_task (line 17) | def do_task(message: str, wait_time: int):

FILE: python/demo19_read_write_lock.py
  function read_func (line 19) | def read_func(wait_time: int):
  function write_func (line 27) | def write_func(wait_time: int):

FILE: python/demo20a01_semaphore.py
  function make_one_sheet (line 15) | def make_one_sheet():
  function combine_one_package (line 23) | def combine_one_package():

FILE: python/demo20a02_semaphore.py
  function make_one_sheet (line 16) | def make_one_sheet():
  function combine_one_package (line 24) | def combine_one_package():

FILE: python/demo20a03_semaphore_deadlock.py
  function make_one_sheet (line 16) | def make_one_sheet():
  function combine_one_package (line 24) | def combine_one_package():

FILE: python/demo20b_semaphore.py
  function make_tire (line 16) | def make_tire():
  function make_chassis (line 27) | def make_chassis():

FILE: python/demo21a01_condition_variable.py
  function foo (line 14) | def foo():
  function bar (line 22) | def bar():

FILE: python/demo21a02_condition_variable.py
  function foo (line 14) | def foo():
  function bar (line 22) | def bar():

FILE: python/demo21a03_condition_variable.py
  function foo (line 14) | def foo():
  function bar (line 22) | def bar():

FILE: python/demo21b_condition_variable.py
  function foo (line 19) | def foo():
  function bar (line 37) | def bar():

FILE: python/demo22a_blocking_queue.py
  function producer (line 12) | def producer(q: Queue):
  function consumer (line 24) | def consumer(q: Queue):

FILE: python/demo22b_blocking_queue.py
  function producer (line 12) | def producer(q: Queue):
  function consumer (line 22) | def consumer(q: Queue):

FILE: python/demo23a_thread_local.py
  function print_local_value (line 14) | def print_local_value():
  function do_task_apple (line 19) | def do_task_apple():
  function do_task_banana (line 26) | def do_task_banana():

FILE: python/demo23b_thread_local.py
  function do_task (line 15) | def do_task(t: int):

FILE: python/demoex_event.py
  function func_speaker (line 16) | def func_speaker(name: str):
  function func_clock (line 27) | def func_clock():

FILE: python/demoex_timer.py
  function func_time_out (line 10) | def func_time_out():

FILE: python/exer01b_max_div.py
  function prepare_arg (line 14) | def prepare_arg(rng_start: int, rng_end: int, num_threads: int) -> list[...
  function do_task (line 28) | def do_task(arg: dict, lst_res: list[dict]):

FILE: python/exer01c_max_div.py
  function prepare_arg (line 15) | def prepare_arg(rng_start: int, rng_end: int, num_threads: int) -> list[...
  function do_task (line 29) | def do_task(arg: dict):

FILE: python/exer02a01_producer_consumer.py
  function producer (line 14) | def producer(q: Queue):
  function consumer (line 24) | def consumer(q: Queue):

FILE: python/exer02a02_producer_consumer.py
  function producer (line 14) | def producer(q: Queue):
  function consumer (line 24) | def consumer(q: Queue):

FILE: python/exer02a03_producer_consumer.py
  function producer (line 14) | def producer(q: Queue):
  function consumer (line 24) | def consumer(name: str, q: Queue):

FILE: python/exer02a04_producer_consumer.py
  function producer (line 14) | def producer(q: Queue, start_value: int):
  function consumer (line 24) | def consumer(q: Queue):

FILE: python/exer02b01_producer_consumer.py
  function producer (line 13) | def producer(
  function consumer (line 29) | def consumer(

FILE: python/exer02b02_producer_consumer.py
  function producer (line 13) | def producer(
  function consumer (line 30) | def consumer(

FILE: python/exer02b03_producer_consumer.py
  function producer (line 13) | def producer(
  function consumer (line 29) | def consumer(

FILE: python/exer02b04_producer_consumer.py
  function producer (line 13) | def producer(
  function consumer (line 30) | def consumer(

FILE: python/exer02c_producer_consumer.py
  class Monitor (line 13) | class Monitor:
    method __init__ (line 14) | def __init__(self, max_queue_size: int, q: list):
    method add (line 22) | def add(self, item):
    method remove (line 33) | def remove(self):
  function producer (line 47) | def producer(mon: Monitor, start_value: int):
  function consumer (line 57) | def consumer(mon: Monitor):

FILE: python/exer03a_readers_writers.py
  class GlobalData (line 12) | class GlobalData:
    method __init__ (line 13) | def __init__(self):
  function do_task_writer (line 21) | def do_task_writer(g: GlobalData, delay_time: int):
  function do_task_reader (line 30) | def do_task_reader(g: GlobalData, delay_time: int):

FILE: python/exer03b_readers_writers.py
  class GlobalData (line 12) | class GlobalData:
    method __init__ (line 13) | def __init__(self):
  function do_task_writer (line 22) | def do_task_writer(g: GlobalData, delay_time: int):
  function do_task_reader (line 35) | def do_task_reader(g: GlobalData, delay_time: int):

FILE: python/exer04_dining_philosophers.py
  function do_task_philosopher (line 10) | def do_task_philosopher(chstk: list, n_philo: int, id_philo: int):

FILE: python/exer05a_product_matrix_vector.py
  function get_scalar_product (line 9) | def get_scalar_product(u: list, v: list):
  function scalar_thfunc (line 15) | def scalar_thfunc(u: list, v: list, res: list, idx_res: int):
  function get_product (line 21) | def get_product(mat: list[list], vec: list) -> list:

FILE: python/exer05b_product_matrix_vector.py
  function get_scalar_product (line 9) | def get_scalar_product(u: list, v: list):
  function scalar_thfunc (line 15) | def scalar_thfunc(u: list, v: list, res: list, idx_res: int):
  function get_transpose_matrix (line 21) | def get_transpose_matrix(mat: list[list]) -> list[list]:
  function get_str_matrix (line 35) | def get_str_matrix(mat: list[list]):
  function get_product (line 43) | def get_product(mata: list[list], matb: list[list]) -> list[list]:

FILE: python/exer06a_blocking_queue.py
  class SynchronousQueue (line 11) | class SynchronousQueue:
    method __init__ (line 12) | def __init__(self):
    method put (line 17) | def put(self, value):
    method take (line 22) | def take(self):
  function producer (line 30) | def producer(syncq: SynchronousQueue):
  function consumer (line 40) | def consumer(syncq: SynchronousQueue):

FILE: python/exer06b01_blocking_queue.py
  class BlockingQueue (line 12) | class BlockingQueue:
    method __init__ (line 13) | def __init__(self, capacity: int):
    method put (line 23) | def put(self, value):
    method take (line 32) | def take(self):
  function producer (line 43) | def producer(q: BlockingQueue):
  function consumer (line 53) | def consumer(q: BlockingQueue):

FILE: python/exer06b02_blocking_queue.py
  class BlockingQueue (line 12) | class BlockingQueue:
    method __init__ (line 13) | def __init__(self, capacity: int):
    method put (line 23) | def put(self, value):
    method take (line 32) | def take(self):
  function producer (line 46) | def producer(q: BlockingQueue):
  function consumer (line 56) | def consumer(q: BlockingQueue):

FILE: python/exer07a_data_server.py
  class Counter (line 13) | class Counter:
  function check_auth_user (line 19) | def check_auth_user():
  function process_files (line 27) | def process_files(lst_file_name: list[str], counter: Counter):
  function process_request (line 44) | def process_request():

FILE: python/exer07b_data_server.py
  function check_auth_user (line 11) | def check_auth_user():
  function process_files (line 19) | def process_files(lst_file_name: list[str], sem: threading.Semaphore):
  function process_request (line 34) | def process_request():

FILE: python/exer07c_data_server.py
  function check_auth_user (line 12) | def check_auth_user():
  function process_files (line 20) | def process_files(lst_file_name: list[str], latch: CountDownLatch):
  function process_request (line 35) | def process_request():

FILE: python/exer07d_data_server.py
  function check_auth_user (line 12) | def check_auth_user():
  function process_files (line 20) | def process_files(lst_file_name: list[str], blkq: Queue):
  function process_request (line 35) | def process_request():

FILE: python/exer08_exec_service_itask.py
  class ITask (line 4) | class ITask(ABC):
    method run (line 6) | def run(self):

FILE: python/exer08_exec_service_main.py
  class MyTask (line 16) | class MyTask(ITask):
    method __init__ (line 17) | def __init__(self, task_id: str):
    method run (line 20) | def run(self):

FILE: python/exer08_exec_service_v0a.py
  class MyExecServiceV0A (line 15) | class MyExecServiceV0A:
    class EmptyTask (line 16) | class EmptyTask(ITask):
      method run (line 17) | def run(self):
    method __init__ (line 21) | def __init__(self, num_threads: int):
    method submit (line 35) | def submit(self, task: ITask):
    method wait_task_done (line 39) | def wait_task_done(self):
    method shutdown (line 45) | def shutdown(self):
    method __thread_worker_func (line 53) | def __thread_worker_func(selfptr: 'MyExecServiceV0A'):

FILE: python/exer08_exec_service_v0b.py
  class MyExecServiceV0B (line 16) | class MyExecServiceV0B:
    class EmptyTask (line 17) | class EmptyTask(ITask):
      method run (line 18) | def run(self):
    method __init__ (line 22) | def __init__(self, num_threads: int):
    method submit (line 38) | def submit(self, task: ITask):
    method wait_task_done (line 42) | def wait_task_done(self):
    method shutdown (line 49) | def shutdown(self):
    method __thread_worker_func (line 65) | def __thread_worker_func(selfptr: 'MyExecServiceV0B'):

FILE: python/exer08_exec_service_v1a.py
  class MyExecServiceV1A (line 14) | class MyExecServiceV1A:
    method __init__ (line 15) | def __init__(self, num_threads: int):
    method submit (line 36) | def submit(self, task: ITask):
    method wait_task_done (line 42) | def wait_task_done(self):
    method shutdown (line 55) | def shutdown(self):
    method __thread_worker_func (line 71) | def __thread_worker_func(selfptr: 'MyExecServiceV1A'):

FILE: python/exer08_exec_service_v1b.py
  class MyExecServiceV1B (line 13) | class MyExecServiceV1B:
    method __init__ (line 14) | def __init__(self, num_threads: int):
    method submit (line 38) | def submit(self, task: ITask):
    method wait_task_done (line 44) | def wait_task_done(self):
    method shutdown (line 56) | def shutdown(self):
    method __thread_worker_func (line 72) | def __thread_worker_func(selfptr: 'MyExecServiceV1B'):

FILE: python/exer08_exec_service_v2a.py
  class MyExecServiceV2A (line 13) | class MyExecServiceV2A:
    method __init__ (line 14) | def __init__(self, num_threads: int):
    method submit (line 35) | def submit(self, task: ITask):
    method wait_task_done (line 41) | def wait_task_done(self):
    method shutdown (line 50) | def shutdown(self):
    method __thread_worker_func (line 66) | def __thread_worker_func(selfptr: 'MyExecServiceV2A'):

FILE: python/exer08_exec_service_v2b.py
  class MyExecServiceV2B (line 13) | class MyExecServiceV2B:
    method __init__ (line 14) | def __init__(self, num_threads: int):
    method submit (line 35) | def submit(self, task: ITask):
    method wait_task_done (line 41) | def wait_task_done(self):
    method shutdown (line 53) | def shutdown(self):
    method __thread_worker_func (line 69) | def __thread_worker_func(selfptr: 'MyExecServiceV2B'):

FILE: python/mylib_latch.py
  class CountDownLatch (line 21) | class CountDownLatch:
    method __init__ (line 22) | def __init__(self, count: int):
    method get_count (line 30) | def get_count(self) -> int:
    method count_down (line 34) | def count_down(self):
    method wait (line 45) | def wait(self):

FILE: python/mylib_rwlock.py
  class ReadWriteLock (line 22) | class ReadWriteLock:
    method __init__ (line 23) | def __init__(self):
    method get_reader_count (line 32) | def get_reader_count(self) -> int:
    method acquire_write (line 36) | def acquire_write(self):
    method release_write (line 41) | def release_write(self):
    method acquire_read (line 45) | def acquire_read(self):
    method release_read (line 53) | def release_read(self):
    method readlock (line 60) | def readlock(self) -> 'ReadWriteLock.ReadLock':
    method writelock (line 64) | def writelock(self) -> 'ReadWriteLock.WriteLock':
    class ReadLock (line 68) | class ReadLock:
      method __init__ (line 69) | def __init__(self, owner: 'ReadWriteLock'):
      method __enter__ (line 72) | def __enter__(self):
      method __exit__ (line 75) | def __exit__(self, exc_type, exc_value, exc_traceback):
    class WriteLock (line 79) | class WriteLock:
      method __init__ (line 80) | def __init__(self, owner: 'ReadWriteLock'):
      method __enter__ (line 83) | def __enter__(self):
      method __exit__ (line 86) | def __exit__(self, exc_type, exc_value, exc_traceback):

FILE: python/mylib_rwlock2.py
  class ReadWriteLock (line 22) | class ReadWriteLock:
    method __init__ (line 23) | def __init__(self):
    method get_reader_count (line 31) | def get_reader_count(self) -> int:
    method acquire_write (line 35) | def acquire_write(self):
    method release_write (line 41) | def release_write(self):
    method acquire_read (line 47) | def acquire_read(self):
    method release_read (line 53) | def release_read(self):
    method readlock (line 60) | def readlock(self) -> 'ReadWriteLock.ReadLock':
    method writelock (line 64) | def writelock(self) -> 'ReadWriteLock.WriteLock':
    class ReadLock (line 68) | class ReadLock:
      method __init__ (line 69) | def __init__(self, owner: 'ReadWriteLock'):
      method __enter__ (line 72) | def __enter__(self):
      method __exit__ (line 75) | def __exit__(self, exc_type, exc_value, exc_traceback):
    class WriteLock (line 79) | class WriteLock:
      method __init__ (line 80) | def __init__(self, owner: 'ReadWriteLock'):
      method __enter__ (line 83) | def __enter__(self):
      method __exit__ (line 86) | def __exit__(self, exc_type, exc_value, exc_traceback):
Condensed preview — 672 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (938K chars).
[
  {
    "path": ".gitignore",
    "chars": 9,
    "preview": ".vscode/\n"
  },
  {
    "path": "LICENSE.txt",
    "chars": 1519,
    "preview": "Copyright (c) 2021, Thanh Nguyen, thanh.it1995 (at) gmail.com\nAll rights reserved.\n\nRedistribution and use in source and"
  },
  {
    "path": "README.md",
    "chars": 8175,
    "preview": "# MULTIPLE THREADING IN PRACTICE\n\n## DESCRIPTION\n\nThis repo helps you to practise multithreading in a logical sequence, "
  },
  {
    "path": "cpp/.gitignore",
    "chars": 13,
    "preview": "a\na.out\ntmp*\n"
  },
  {
    "path": "cpp/README.md",
    "chars": 1456,
    "preview": "# C++ MULTITHREADING\n\n## DESCRIPTION\n\nMultithreading in C++.\n\n&nbsp;\n\n## PROJECT STRUCTURE\n\n| Directory name | Descripti"
  },
  {
    "path": "cpp/cpp-boost/demo00.cpp",
    "chars": 401,
    "preview": "/*\nINTRODUCTION TO MULTITHREADING\nYou should try running this app several times and see results.\n*/\n\n\n#include <iostream"
  },
  {
    "path": "cpp/cpp-boost/demo01a01-hello.cpp",
    "chars": 337,
    "preview": "/*\nHELLO WORLD VERSION MULTITHREADING\nVersion A01: Using functions\n*/\n\n\n#include <iostream>\n#include <boost/thread.hpp>\n"
  },
  {
    "path": "cpp/cpp-boost/demo01a02-hello.cpp",
    "chars": 362,
    "preview": "/*\nHELLO WORLD VERSION MULTITHREADING\nVersion A02: Using functions allowing passing 2 arguments\n*/\n\n\n#include <iostream>"
  },
  {
    "path": "cpp/cpp-boost/demo01b-hello-class01.cpp",
    "chars": 474,
    "preview": "/*\nHELLO WORLD VERSION MULTITHREADING\nVersion B: Using class methods\n*/\n\n\n#include <iostream>\n#include <string>\n#include"
  },
  {
    "path": "cpp/cpp-boost/demo01b-hello-class02.cpp",
    "chars": 559,
    "preview": "/*\nHELLO WORLD VERSION MULTITHREADING\nVersion B: Using class methods\n*/\n\n\n#include <iostream>\n#include <string>\n#include"
  },
  {
    "path": "cpp/cpp-boost/demo01b-hello-class03.cpp",
    "chars": 451,
    "preview": "/*\nHELLO WORLD VERSION MULTITHREADING\nVersion B: Using class methods\n*/\n\n\n#include <iostream>\n#include <string>\n#include"
  },
  {
    "path": "cpp/cpp-boost/demo01b-hello-functor.cpp",
    "chars": 376,
    "preview": "/*\nHELLO WORLD VERSION MULTITHREADING\nVersion B: Using functors\n*/\n\n\n#include <iostream>\n#include <string>\n#include <boo"
  },
  {
    "path": "cpp/cpp-boost/demo02-join.cpp",
    "chars": 357,
    "preview": "/*\nTHREAD JOINS\n*/\n\n\n#include <iostream>\n#include <boost/thread.hpp>\nusing namespace std;\n\n\n\nvoid doHeavyTask() {\n    //"
  },
  {
    "path": "cpp/cpp-boost/demo03a-pass-arg.cpp",
    "chars": 694,
    "preview": "/*\nPASSING ARGUMENTS\nVersion A: Passing multiple arguments with various data types\n*/\n\n\n#include <iostream>\n#include <cs"
  },
  {
    "path": "cpp/cpp-boost/demo03b-pass-arg.cpp",
    "chars": 428,
    "preview": "/*\nPASSING ARGUMENTS\nVersion B: Passing constant references\n*/\n\n\n#include <iostream>\n#include <string>\n#include <boost/t"
  },
  {
    "path": "cpp/cpp-boost/demo03c-pass-arg.cpp",
    "chars": 591,
    "preview": "/*\nPASSING ARGUMENTS\nVersion C: Passing normal references\n*/\n\n\n#include <iostream>\n#include <string>\n#include <boost/ref"
  },
  {
    "path": "cpp/cpp-boost/demo04a-sleep.cpp",
    "chars": 474,
    "preview": "/*\nSLEEP\nVersion A: Sleep for a specific duration\n*/\n\n\n#include <iostream>\n#include <string>\n#include <boost/chrono.hpp>"
  },
  {
    "path": "cpp/cpp-boost/demo04b-sleep.cpp",
    "chars": 946,
    "preview": "/*\nSLEEP\nVersion B: Sleep until a specific time point\n*/\n\n\n#include <iostream>\n#include <string>\n#include <boost/chrono."
  },
  {
    "path": "cpp/cpp-boost/demo05-id.cpp",
    "chars": 501,
    "preview": "/*\nGETTING THREAD'S ID\n*/\n\n\n#include <iostream>\n#include <boost/chrono.hpp>\n#include <boost/thread.hpp>\nusing namespace "
  },
  {
    "path": "cpp/cpp-boost/demo06a-list-threads.cpp",
    "chars": 478,
    "preview": "/*\nLIST OF MULTIPLE THREADS\nVersion A: Using standard arrays\n*/\n\n\n#include <iostream>\n#include <boost/thread.hpp>\nusing "
  },
  {
    "path": "cpp/cpp-boost/demo06b-list-threads.cpp",
    "chars": 631,
    "preview": "/*\nLIST OF MULTIPLE THREADS\nVersion B: Using the std::vector\n*/\n\n\n#include <iostream>\n#include <vector>\n#include <boost/"
  },
  {
    "path": "cpp/cpp-boost/demo06c-list-threads.cpp",
    "chars": 525,
    "preview": "/*\nLIST OF MULTIPLE THREADS\nVersion C: Using the boost::thread_group\n*/\n\n\n#include <iostream>\n#include <boost/bind/bind."
  },
  {
    "path": "cpp/cpp-boost/demo07-terminate.cpp",
    "chars": 531,
    "preview": "/*\nFORCING A THREAD TO TERMINATE (i.e. killing the thread)\n*/\n\n\n#include <iostream>\n#include <boost/chrono.hpp>\n#include"
  },
  {
    "path": "cpp/cpp-boost/demo08-return-value.cpp",
    "chars": 691,
    "preview": "/*\nGETTING RETURNED VALUES FROM THREADS\nUsing pointers or references (traditional way)\n*/\n\n\n#include <iostream>\n#include"
  },
  {
    "path": "cpp/cpp-boost/demo09-detach.cpp",
    "chars": 580,
    "preview": "/*\nTHREAD DETACHING\n*/\n\n\n#include <iostream>\n#include <boost/chrono.hpp>\n#include <boost/thread.hpp>\nusing namespace std"
  },
  {
    "path": "cpp/cpp-boost/demo10-yield.cpp",
    "chars": 759,
    "preview": "/*\nTHREAD YIELDING\n*/\n\n\n#include <iostream>\n#include <boost/chrono.hpp>\n#include <boost/thread.hpp>\n#include \"mylib-time"
  },
  {
    "path": "cpp/cpp-boost/demo11a-exec-service.cpp",
    "chars": 721,
    "preview": "/*\nEXECUTOR SERVICES AND THREAD POOLS\n*/\n\n\n#include <iostream>\n#include <boost/bind/bind.hpp>\n#include <boost/thread.hpp"
  },
  {
    "path": "cpp/cpp-boost/demo11b-exec-service.cpp",
    "chars": 780,
    "preview": "/*\nEXECUTOR SERVICES AND THREAD POOLS\n*/\n\n\n#include <iostream>\n#include <boost/bind/bind.hpp>\n#include <boost/chrono.hpp"
  },
  {
    "path": "cpp/cpp-boost/demo12a-race-condition.cpp",
    "chars": 476,
    "preview": "/*\nRACE CONDITIONS\n*/\n\n\n#include <iostream>\n#include <boost/chrono.hpp>\n#include <boost/thread.hpp>\nusing namespace std;"
  },
  {
    "path": "cpp/cpp-boost/demo12b01-data-race-single.cpp",
    "chars": 622,
    "preview": "/*\nDATA RACES\nVersion 01: Without multithreading\n*/\n\n\n#include <iostream>\n#include <vector>\n#include <numeric>\nusing nam"
  },
  {
    "path": "cpp/cpp-boost/demo12b02-data-race-multi.cpp",
    "chars": 848,
    "preview": "/*\nDATA RACES\nVersion 02: Multithreading\n*/\n\n\n#include <iostream>\n#include <vector>\n#include <numeric>\n#include <boost/r"
  },
  {
    "path": "cpp/cpp-boost/demo12c01-race-cond-data-race.cpp",
    "chars": 637,
    "preview": "/*\nRACE CONDITIONS AND DATA RACES\n*/\n\n\n#include <iostream>\n#include <boost/chrono.hpp>\n#include <boost/thread.hpp>\nusing"
  },
  {
    "path": "cpp/cpp-boost/demo12c02-race-cond-data-race.cpp",
    "chars": 862,
    "preview": "/*\nRACE CONDITIONS AND DATA RACES\n*/\n\n\n#include <iostream>\n#include <boost/chrono.hpp>\n#include <boost/thread.hpp>\nusing"
  },
  {
    "path": "cpp/cpp-boost/demo13a-mutex.cpp",
    "chars": 635,
    "preview": "/*\nMUTEXES\n*/\n\n\n#include <iostream>\n#include <boost/chrono.hpp>\n#include <boost/thread.hpp>\nusing namespace std;\n\n\n\nboos"
  },
  {
    "path": "cpp/cpp-boost/demo13b01-mutex.cpp",
    "chars": 762,
    "preview": "/*\nMUTEXES\n*/\n\n\n#include <iostream>\n#include <boost/chrono.hpp>\n#include <boost/thread.hpp>\nusing namespace std;\n\n\n\nboos"
  },
  {
    "path": "cpp/cpp-boost/demo13b02-mutex.cpp",
    "chars": 1123,
    "preview": "/*\nMUTEXES\n\nboost::unique_lock is more complex than boost::lock_guard:\nNot only does it provide for RAII-style locking, "
  },
  {
    "path": "cpp/cpp-boost/demo13c-mutex-trylock.cpp",
    "chars": 713,
    "preview": "/*\nMUTEXES\nLocking with a nonblocking mutex\n*/\n\n\n#include <iostream>\n#include <boost/chrono.hpp>\n#include <boost/thread."
  },
  {
    "path": "cpp/cpp-boost/demo14-synchronized-block.cpp",
    "chars": 1157,
    "preview": "/*\nSYNCHRONIZED BLOCKS\n\nSynchronized blocks in C++ Boost threading are not supported by default.\nTo demonstate synchroni"
  },
  {
    "path": "cpp/cpp-boost/demo15a-deadlock.cpp",
    "chars": 525,
    "preview": "/*\nDEADLOCK\nVersion A\n*/\n\n\n#include <iostream>\n#include <string>\n#include <boost/thread.hpp>\nusing namespace std;\n\n\n\nboo"
  },
  {
    "path": "cpp/cpp-boost/demo15b-deadlock.cpp",
    "chars": 949,
    "preview": "/*\nDEADLOCK\nVersion B\n*/\n\n\n#include <iostream>\n#include <boost/chrono.hpp>\n#include <boost/thread.hpp>\nusing namespace s"
  },
  {
    "path": "cpp/cpp-boost/demo16-monitor.cpp",
    "chars": 1025,
    "preview": "/*\nMONITORS\nImplementation of a monitor for managing a counter\n*/\n\n\n#include <iostream>\n#include <boost/chrono.hpp>\n#inc"
  },
  {
    "path": "cpp/cpp-boost/demo17a-reentrant-lock.cpp",
    "chars": 586,
    "preview": "/*\nREENTRANT LOCKS (RECURSIVE MUTEXES)\nVersion A: Introduction to reentrant locks\n*/\n\n\n#include <iostream>\n#include <boo"
  },
  {
    "path": "cpp/cpp-boost/demo17b-reentrant-lock.cpp",
    "chars": 749,
    "preview": "/*\nREENTRANT LOCKS (RECURSIVE MUTEXES)\nVersion B: Solving the problem from version A\n*/\n\n\n#include <iostream>\n#include <"
  },
  {
    "path": "cpp/cpp-boost/demo17c-reentrant-lock.cpp",
    "chars": 1170,
    "preview": "/*\nREENTRANT LOCKS (RECURSIVE MUTEXES)\nVersion C: A multithreaded app example\n*/\n\n\n#include <iostream>\n#include <boost/c"
  },
  {
    "path": "cpp/cpp-boost/demo18a01-barrier.cpp",
    "chars": 1173,
    "preview": "/*\nBARRIERS AND LATCHES\nVersion A: Cyclic barriers\n*/\n\n\n#include <iostream>\n#include <string>\n#include <boost/tuple/tupl"
  },
  {
    "path": "cpp/cpp-boost/demo18a02-barrier.cpp",
    "chars": 1262,
    "preview": "/*\nBARRIERS AND LATCHES\nVersion A: Cyclic barriers\n*/\n\n\n#include <iostream>\n#include <string>\n#include <boost/tuple/tupl"
  },
  {
    "path": "cpp/cpp-boost/demo18a03-barrier.cpp",
    "chars": 1215,
    "preview": "/*\nBARRIERS AND LATCHES\nVersion A: Cyclic barriers\n*/\n\n\n#include <iostream>\n#include <string>\n#include <boost/tuple/tupl"
  },
  {
    "path": "cpp/cpp-boost/demo18b01-latch.cpp",
    "chars": 1168,
    "preview": "/*\nBARRIERS AND LATCHES\nVersion B: Count-down latches\n*/\n\n\n#include <iostream>\n#include <string>\n#include <boost/tuple/t"
  },
  {
    "path": "cpp/cpp-boost/demo18b02-latch.cpp",
    "chars": 1357,
    "preview": "/*\nBARRIERS AND LATCHES\nVersion B: Count-down latches\n\nMain thread waits for 3 child threads to get enough data to progr"
  },
  {
    "path": "cpp/cpp-boost/demo19a-read-write-lock.cpp",
    "chars": 1488,
    "preview": "/*\nREAD-WRITE LOCKS\n*/\n\n\n#include <iostream>\n#include <numeric>\n#include <boost/chrono.hpp>\n#include <boost/thread.hpp>\n"
  },
  {
    "path": "cpp/cpp-boost/demo19b-read-write-lock.cpp",
    "chars": 1605,
    "preview": "/*\nREAD-WRITE LOCKS\n*/\n\n\n#include <iostream>\n#include <numeric>\n#include <boost/chrono.hpp>\n#include <boost/thread.hpp>\n"
  },
  {
    "path": "cpp/cpp-boost/demo20a01-semaphore.cpp",
    "chars": 992,
    "preview": "/*\nSEMAPHORES\nVersion A: Paper sheets and packages\n\nSemaphores in C++ Boost threading are not supported by default.\nSo, "
  },
  {
    "path": "cpp/cpp-boost/demo20a02-semaphore.cpp",
    "chars": 1108,
    "preview": "/*\nSEMAPHORES\nVersion A: Paper sheets and packages\n\nSemaphores in C++ Boost threading are not supported by default.\nSo, "
  },
  {
    "path": "cpp/cpp-boost/demo20a03-semaphore-deadlock.cpp",
    "chars": 1146,
    "preview": "/*\nSEMAPHORES\nVersion A: Paper sheets and packages\n\nSemaphores in C++ Boost threading are not supported by default.\nSo, "
  },
  {
    "path": "cpp/cpp-boost/demo20b-semaphore.cpp",
    "chars": 1202,
    "preview": "/*\nSEMAPHORES\nVersion B: Tires and chassis\n\nSemaphores in C++ Boost threading are not supported by default.\nSo, I use my"
  },
  {
    "path": "cpp/cpp-boost/demo21a01-condition-variable.cpp",
    "chars": 608,
    "preview": "/*\nCONDITION VARIABLES\n*/\n\n\n#include <iostream>\n#include <boost/chrono.hpp>\n#include <boost/thread.hpp>\nusing namespace "
  },
  {
    "path": "cpp/cpp-boost/demo21a02-condition-variable.cpp",
    "chars": 807,
    "preview": "/*\nCONDITION VARIABLES\n*/\n\n\n#include <iostream>\n#include <boost/chrono.hpp>\n#include <boost/thread.hpp>\nusing namespace "
  },
  {
    "path": "cpp/cpp-boost/demo21a03-condition-variable.cpp",
    "chars": 784,
    "preview": "/*\nCONDITION VARIABLES\n*/\n\n\n#include <iostream>\n#include <boost/chrono.hpp>\n#include <boost/thread.hpp>\nusing namespace "
  },
  {
    "path": "cpp/cpp-boost/demo21b-condition-variable.cpp",
    "chars": 1443,
    "preview": "/*\nCONDITION VARIABLES\n*/\n\n\n#include <iostream>\n#include <boost/chrono.hpp>\n#include <boost/thread.hpp>\nusing namespace "
  },
  {
    "path": "cpp/cpp-boost/demo22a-blocking-queue.cpp",
    "chars": 1152,
    "preview": "/*\nBLOCKING QUEUES\nVersion A: A slow producer and a fast consumer\n\nBlocking queues in C++ Boost threading are not suppor"
  },
  {
    "path": "cpp/cpp-boost/demo22b-blocking-queue.cpp",
    "chars": 1238,
    "preview": "/*\nBLOCKING QUEUES\nVersion B: A fast producer and a slow consumer\n\nBlocking queues in C++ Boost threading are not suppor"
  },
  {
    "path": "cpp/cpp-boost/demo23a-thread-local.cpp",
    "chars": 773,
    "preview": "/*\nTHREAD-LOCAL STORAGE\nIntroduction\n    The basic way to use thread-local storage\n*/\n\n\n#include <iostream>\n#include <st"
  },
  {
    "path": "cpp/cpp-boost/demo23b-thread-local.cpp",
    "chars": 939,
    "preview": "/*\nTHREAD-LOCAL STORAGE\nAvoiding synchronization using thread-local storage\n*/\n\n\n#include <iostream>\n#include <boost/chr"
  },
  {
    "path": "cpp/cpp-boost/demo24-volatile.cpp",
    "chars": 496,
    "preview": "/*\nTHE VOLATILE KEYWORD\n*/\n\n\n#include <iostream>\n#include <boost/chrono.hpp>\n#include <boost/thread.hpp>\nusing namespace"
  },
  {
    "path": "cpp/cpp-boost/demo25a-atomic.cpp",
    "chars": 525,
    "preview": "/*\nATOMIC ACCESS\n*/\n\n\n#include <iostream>\n#include <boost/chrono.hpp>\n#include <boost/thread.hpp>\nusing namespace std;\n\n"
  },
  {
    "path": "cpp/cpp-boost/demo25b-atomic.cpp",
    "chars": 555,
    "preview": "/*\nATOMIC ACCESS\n*/\n\n\n#include <iostream>\n#include <boost/chrono.hpp>\n#include <boost/thread.hpp>\nusing namespace std;\n\n"
  },
  {
    "path": "cpp/cpp-boost/demoex-async-future.cpp",
    "chars": 1180,
    "preview": "/*\nASYNCHRONOUS PROGRAMMING WITH THE FUTURE\n*/\n\n\n#include <iostream>\n#include <boost/ref.hpp>\n#include <boost/move/move."
  },
  {
    "path": "cpp/cpp-boost/exer01a-max-div.cpp",
    "chars": 1053,
    "preview": "/*\nMAXIMUM NUMBER OF DIVISORS\n*/\n\n\n#include <iostream>\n#include \"mylib-time.hpp\"\nusing namespace std;\n\n\n\ntypedef boost::"
  },
  {
    "path": "cpp/cpp-boost/exer01b-max-div.cpp",
    "chars": 2674,
    "preview": "/*\nMAXIMUM NUMBER OF DIVISORS\n*/\n\n\n#include <iostream>\n#include <vector>\n#include <algorithm>\n#include <boost/thread.hpp"
  },
  {
    "path": "cpp/cpp-boost/exer01c-max-div.cpp",
    "chars": 2594,
    "preview": "/*\nMAXIMUM NUMBER OF DIVISORS\n*/\n\n\n#include <iostream>\n#include <vector>\n#include <algorithm>\n#include <boost/thread.hpp"
  },
  {
    "path": "cpp/cpp-boost/exer02a01-producer-consumer.cpp",
    "chars": 826,
    "preview": "/*\nTHE PRODUCER-CONSUMER PROBLEM\n\nSOLUTION TYPE A: USING BLOCKING QUEUES\n    Version A01: 1 slow producer, 1 fast consum"
  },
  {
    "path": "cpp/cpp-boost/exer02a02-producer-consumer.cpp",
    "chars": 902,
    "preview": "/*\nTHE PRODUCER-CONSUMER PROBLEM\n\nSOLUTION TYPE A: USING BLOCKING QUEUES\n    Version A02: 2 slow producers, 1 fast consu"
  },
  {
    "path": "cpp/cpp-boost/exer02a03-producer-consumer.cpp",
    "chars": 971,
    "preview": "/*\nTHE PRODUCER-CONSUMER PROBLEM\n\nSOLUTION TYPE A: USING BLOCKING QUEUES\n    Version A03: 1 slow producer, 2 fast consum"
  },
  {
    "path": "cpp/cpp-boost/exer02a04-producer-consumer.cpp",
    "chars": 1241,
    "preview": "/*\nTHE PRODUCER-CONSUMER PROBLEM\n\nSOLUTION TYPE A: USING BLOCKING QUEUES\n    Version A04: Multiple fast producers, multi"
  },
  {
    "path": "cpp/cpp-boost/exer02b01-producer-consumer.cpp",
    "chars": 1201,
    "preview": "/*\nTHE PRODUCER-CONSUMER PROBLEM\n\nSOLUTION TYPE B: USING SEMAPHORES\n    Version B01: 1 slow producer, 1 fast consumer\n*/"
  },
  {
    "path": "cpp/cpp-boost/exer02b02-producer-consumer.cpp",
    "chars": 1337,
    "preview": "/*\nTHE PRODUCER-CONSUMER PROBLEM\n\nSOLUTION TYPE B: USING SEMAPHORES\n    Version B02: 2 slow producers, 1 fast consumer\n*"
  },
  {
    "path": "cpp/cpp-boost/exer02b03-producer-consumer.cpp",
    "chars": 1335,
    "preview": "/*\nTHE PRODUCER-CONSUMER PROBLEM\n\nSOLUTION TYPE B: USING SEMAPHORES\n    Version B03: 2 fast producers, 1 slow consumer\n*"
  },
  {
    "path": "cpp/cpp-boost/exer02b04-producer-consumer.cpp",
    "chars": 1659,
    "preview": "/*\nTHE PRODUCER-CONSUMER PROBLEM\n\nSOLUTION TYPE B: USING SEMAPHORES\n    Version B04: Multiple fast producers, multiple s"
  },
  {
    "path": "cpp/cpp-boost/exer02c-producer-consumer.cpp",
    "chars": 2508,
    "preview": "/*\nTHE PRODUCER-CONSUMER PROBLEM\n\nSOLUTION TYPE C: USING CONDITION VARIABLES & MONITORS\n    Multiple fast producers, mul"
  },
  {
    "path": "cpp/cpp-boost/exer03a-readers-writers.cpp",
    "chars": 1888,
    "preview": "/*\nTHE READERS-WRITERS PROBLEM\nSolution for the first readers-writers problem\n*/\n\n\n#include <iostream>\n#include <boost/c"
  },
  {
    "path": "cpp/cpp-boost/exer03b-readers-writers.cpp",
    "chars": 2057,
    "preview": "/*\nTHE READERS-WRITERS PROBLEM\nSolution for the third readers-writers problem\n*/\n\n\n#include <iostream>\n#include <boost/c"
  },
  {
    "path": "cpp/cpp-boost/exer04-dining-philosophers.cpp",
    "chars": 1322,
    "preview": "/*\nTHE DINING PHILOSOPHERS PROBLEM\n*/\n\n\n#include <iostream>\n#include <boost/chrono.hpp>\n#include <boost/thread.hpp>\nusin"
  },
  {
    "path": "cpp/cpp-boost/exer05-util.hpp",
    "chars": 297,
    "preview": "#ifndef _EXER05_UTIL_HPP_\n#define _EXER05_UTIL_HPP_\n\n\n\nvoid getScalarProduct(double const* u, double const* v, int sizeV"
  },
  {
    "path": "cpp/cpp-boost/exer05a-product-matrix-vector.cpp",
    "chars": 1201,
    "preview": "/*\nMATRIX-VECTOR MULTIPLICATION\n*/\n\n\n#include <iostream>\n#include <vector>\n#include <boost/assign/std/vector.hpp>\n#inclu"
  },
  {
    "path": "cpp/cpp-boost/exer05b-product-matrix-matrix.cpp",
    "chars": 2059,
    "preview": "/*\nMATRIX-MATRIX MULTIPLICATION (DOT PRODUCT)\n*/\n\n\n#include <iostream>\n#include <vector>\n#include <boost/assign/std/vect"
  },
  {
    "path": "cpp/cpp-boost/exer06a-blocking-queue.cpp",
    "chars": 1494,
    "preview": "/*\nBLOCKING QUEUE IMPLEMENTATION\nVersion A: Synchronous queues\n*/\n\n\n#include <iostream>\n#include <string>\n#include <boos"
  },
  {
    "path": "cpp/cpp-boost/exer06b01-blocking-queue.cpp",
    "chars": 2088,
    "preview": "/*\nBLOCKING QUEUE IMPLEMENTATION\nVersion B01: General blocking queues\n             Underlying mechanism: Semaphores\n*/\n\n"
  },
  {
    "path": "cpp/cpp-boost/exer06b02-blocking-queue.cpp",
    "chars": 2303,
    "preview": "/*\nBLOCKING QUEUE IMPLEMENTATION\nVersion B02: General blocking queues\n             Underlying mechanism: Condition varia"
  },
  {
    "path": "cpp/cpp-boost/exer07a-data-server.cpp",
    "chars": 2095,
    "preview": "/*\nTHE DATA SERVER PROBLEM\nVersion A: Solving the problem using a condition variable\n*/\n\n\n#include <iostream>\n#include <"
  },
  {
    "path": "cpp/cpp-boost/exer07b-data-server.cpp",
    "chars": 1720,
    "preview": "/*\nTHE DATA SERVER PROBLEM\nVersion B: Solving the problem using a semaphore\n*/\n\n\n#include <iostream>\n#include <string>\n#"
  },
  {
    "path": "cpp/cpp-boost/exer07c-data-server.cpp",
    "chars": 1713,
    "preview": "/*\nTHE DATA SERVER PROBLEM\nVersion C: Solving the problem using a count-down latch\n*/\n\n\n#include <iostream>\n#include <st"
  },
  {
    "path": "cpp/cpp-boost/exer07d-data-server.cpp",
    "chars": 1786,
    "preview": "/*\nTHE DATA SERVER PROBLEM\nVersion D: Solving the problem using a blocking queue\n*/\n\n\n#include <iostream>\n#include <stri"
  },
  {
    "path": "cpp/cpp-boost/exer08-exec-service-itask.hpp",
    "chars": 213,
    "preview": "#ifndef _MY_EXEC_SERVICE_ITASK_HPP_\n#define _MY_EXEC_SERVICE_ITASK_HPP_\n\n\n\n// interface ITask\nclass ITask {\npublic:\n    "
  },
  {
    "path": "cpp/cpp-boost/exer08-exec-service-main.cpp",
    "chars": 1228,
    "preview": "/*\nEXECUTOR SERVICE & THREAD POOL IMPLEMENTATION\n*/\n\n\n#include <iostream>\n#include <boost/chrono.hpp>\n#include <boost/th"
  },
  {
    "path": "cpp/cpp-boost/exer08-exec-service-v0a.hpp",
    "chars": 2135,
    "preview": "/*\nMY EXECUTOR SERVICE\n\nVersion 0A: The easiest executor service\n- It uses a blocking queue as underlying mechanism.\n*/\n"
  },
  {
    "path": "cpp/cpp-boost/exer08-exec-service-v0b.hpp",
    "chars": 2894,
    "preview": "/*\nMY EXECUTOR SERVICE\n\nVersion 0B: The easiest executor service\n- It uses a blocking queue as underlying mechanism.\n- I"
  },
  {
    "path": "cpp/cpp-boost/exer08-exec-service-v1a.hpp",
    "chars": 3663,
    "preview": "/*\nMY EXECUTOR SERVICE\n\nVersion 1A: Simple executor service\n- Method \"waitTaskDone\" invokes thread sleeps in loop (which"
  },
  {
    "path": "cpp/cpp-boost/exer08-exec-service-v1b.hpp",
    "chars": 3931,
    "preview": "/*\nMY EXECUTOR SERVICE\n\nVersion 1B: Simple executor service\n- Method \"waitTaskDone\" uses a condition variable to synchro"
  },
  {
    "path": "cpp/cpp-boost/exer08-exec-service-v2a.hpp",
    "chars": 4110,
    "preview": "/*\nMY EXECUTOR SERVICE\n\nVersion 2A: The executor service storing running tasks\n- Method \"waitTaskDone\" uses a semaphore "
  },
  {
    "path": "cpp/cpp-boost/exer08-exec-service-v2b.hpp",
    "chars": 4080,
    "preview": "/*\nMY EXECUTOR SERVICE\n\nVersion 2B: The executor service storing running tasks\n- Method \"waitTaskDone\" uses a condition "
  },
  {
    "path": "cpp/cpp-boost/mylib-blockingqueue.hpp",
    "chars": 2688,
    "preview": "/******************************************************\n*\n* File name:    mylib-blockingqueue.hpp\n*\n* Author:       Name"
  },
  {
    "path": "cpp/cpp-boost/mylib-random.hpp",
    "chars": 1493,
    "preview": "/******************************************************\n*\n* File name:    mylib-random.hpp\n*\n* Author:       Name:   Tha"
  },
  {
    "path": "cpp/cpp-boost/mylib-semaphore.hpp",
    "chars": 1943,
    "preview": "/******************************************************\n*\n* File name:    mylib-semaphore.hpp\n*\n* Author:       Name:   "
  },
  {
    "path": "cpp/cpp-boost/mylib-time.hpp",
    "chars": 2362,
    "preview": "/******************************************************\n*\n* File name:    mylib-time.hpp\n*\n* Author:       Name:   Thanh"
  },
  {
    "path": "cpp/cpp-pthread/demo00.cpp",
    "chars": 536,
    "preview": "/*\nINTRODUCTION TO MULTITHREADING\nYou should try running this app several times and see results.\n*/\n\n\n#include <iostream"
  },
  {
    "path": "cpp/cpp-pthread/demo01-hello.cpp",
    "chars": 516,
    "preview": "/*\nHELLO WORLD VERSION MULTITHREADING\n*/\n\n\n#include <iostream>\n#include <pthread.h>\nusing namespace std;\n\n\n\nvoid* doTask"
  },
  {
    "path": "cpp/cpp-pthread/demo02-join.cpp",
    "chars": 492,
    "preview": "/*\nTHREAD JOINS\n*/\n\n\n#include <iostream>\n#include <pthread.h>\nusing namespace std;\n\n\n\nvoid* doHeavyTask(void*) {\n    // "
  },
  {
    "path": "cpp/cpp-pthread/demo03a01-pass-arg.cpp",
    "chars": 694,
    "preview": "/*\nPASSING ARGUMENTS\nVersion A01: The problem\n\nThe id in statement \"hello pthread with id...\" might be DUPLICATED!!!\nRea"
  },
  {
    "path": "cpp/cpp-pthread/demo03a02-pass-arg.cpp",
    "chars": 599,
    "preview": "/*\nPASSING ARGUMENTS\nVersion A02: Solving the problem\n*/\n\n\n#include <iostream>\n#include <pthread.h>\nusing namespace std;"
  },
  {
    "path": "cpp/cpp-pthread/demo03b01-pass-arg.cpp",
    "chars": 667,
    "preview": "/*\nPASSING MULTIPLE ARGUMENTS\nSolution 01: Creating a custom struct\n*/\n\n\n#include <iostream>\n#include <string>\n#include "
  },
  {
    "path": "cpp/cpp-pthread/demo03b02-pass-arg.cpp",
    "chars": 710,
    "preview": "/*\nPASSING MULTIPLE ARGUMENTS\nSolution 02: Using std::tuple\n*/\n\n\n#include <iostream>\n#include <string>\n#include <tuple>\n"
  },
  {
    "path": "cpp/cpp-pthread/demo04-sleep.cpp",
    "chars": 483,
    "preview": "/*\nSLEEP\n*/\n\n\n#include <iostream>\n#include <unistd.h>\n#include <pthread.h>\nusing namespace std;\n\n\n\nvoid* doTask(void* ar"
  },
  {
    "path": "cpp/cpp-pthread/demo05-id.cpp",
    "chars": 614,
    "preview": "/*\nGETTING THREAD'S ID\n*/\n\n\n#include <iostream>\n#include <unistd.h>\n#include <pthread.h>\nusing namespace std;\n\n\n\nvoid* d"
  },
  {
    "path": "cpp/cpp-pthread/demo06a-list-threads.cpp",
    "chars": 654,
    "preview": "/*\nLIST OF MULTIPLE THREADS\nVersion A: Using standard arrays\n*/\n\n\n#include <iostream>\n#include <pthread.h>\nusing namespa"
  },
  {
    "path": "cpp/cpp-pthread/demo06b-list-threads.cpp",
    "chars": 688,
    "preview": "/*\nLIST OF MULTIPLE THREADS\nVersion B: Using the std::vector\n*/\n\n\n#include <iostream>\n#include <vector>\n#include <pthrea"
  },
  {
    "path": "cpp/cpp-pthread/demo07a-terminate.cpp",
    "chars": 600,
    "preview": "/*\nFORCING A THREAD TO TERMINATE (i.e. killing the thread)\nVersion A: Using the flag 'isRunning'\n*/\n\n\n#include <iostream"
  },
  {
    "path": "cpp/cpp-pthread/demo07b-terminate.cpp",
    "chars": 546,
    "preview": "/*\nFORCING A THREAD TO TERMINATE (i.e. killing the thread)\nVersion B: Using pthread_cancel\n*/\n\n\n#include <iostream>\n#inc"
  },
  {
    "path": "cpp/cpp-pthread/demo08a-return-value.cpp",
    "chars": 643,
    "preview": "/*\nGETTING RETURNED VALUES FROM THREADS\nVersion A: Values returned via pointers passed from arguments\n*/\n\n\n#include <ios"
  },
  {
    "path": "cpp/cpp-pthread/demo08b-return-value.cpp",
    "chars": 626,
    "preview": "/*\nGETTING RETURNED VALUES FROM THREADS\nVersion B: Values returned via pthread_exit\n*/\n\n\n#include <iostream>\n#include <p"
  },
  {
    "path": "cpp/cpp-pthread/demo09a-detach.cpp",
    "chars": 813,
    "preview": "/*\nTHREAD DETACHING\n*/\n\n\n#include <iostream>\n#include <unistd.h>\n#include <pthread.h>\nusing namespace std;\n\n\n\nvoid* foo("
  },
  {
    "path": "cpp/cpp-pthread/demo09b-detach.cpp",
    "chars": 594,
    "preview": "/*\nTHREAD DETACHING\n*/\n\n\n#include <iostream>\n#include <unistd.h>\n#include <pthread.h>\nusing namespace std;\n\n\n\nvoid* foo("
  },
  {
    "path": "cpp/cpp-pthread/demo10-yield.cpp",
    "chars": 732,
    "preview": "/*\nTHREAD YIELDING\n*/\n\n\n#include <iostream>\n#include <sched.h>\n#include <pthread.h>\n#include <chrono>\n#include \"../cpp-s"
  },
  {
    "path": "cpp/cpp-pthread/demo11a-exec-service.cpp",
    "chars": 837,
    "preview": "/*\nEXECUTOR SERVICES AND THREAD POOLS\n\nExecutor services in C++ POSIX threading are not supported by default.\nSo, I use "
  },
  {
    "path": "cpp/cpp-pthread/demo11b-exec-service.cpp",
    "chars": 847,
    "preview": "/*\nEXECUTOR SERVICES AND THREAD POOLS\n\nExecutor services in C++ POSIX threading are not supported by default.\nSo, I use "
  },
  {
    "path": "cpp/cpp-pthread/demo12a-race-condition.cpp",
    "chars": 647,
    "preview": "/*\nRACE CONDITIONS\n*/\n\n\n#include <iostream>\n#include <pthread.h>\n#include <unistd.h>\nusing namespace std;\n\n\n\nvoid* doTas"
  },
  {
    "path": "cpp/cpp-pthread/demo12b01-data-race-single.cpp",
    "chars": 613,
    "preview": "/*\nDATA RACES\nVersion 01: Without multithreading\n*/\n\n\n#include <iostream>\n#include <cstdlib>\nusing namespace std;\n\n\n\nint"
  },
  {
    "path": "cpp/cpp-pthread/demo12b02-data-race-multi.cpp",
    "chars": 986,
    "preview": "/*\nDATA RACES\nVersion 02: Multithreading\n*/\n\n\n#include <iostream>\n#include <cstdlib>\n#include <pthread.h>\nusing namespac"
  },
  {
    "path": "cpp/cpp-pthread/demo12bex-data-race-fork.cpp",
    "chars": 586,
    "preview": "/*\nDATA RACES\n*/\n\n\n#include <iostream>\n#include <fstream>\n#include <unistd.h>\nusing namespace std;\n\n\n\nint main() {\n    i"
  },
  {
    "path": "cpp/cpp-pthread/demo12c01-race-cond-data-race.cpp",
    "chars": 744,
    "preview": "/*\nRACE CONDITIONS AND DATA RACES\n*/\n\n\n#include <iostream>\n#include <unistd.h>\n#include <pthread.h>\nusing namespace std;"
  },
  {
    "path": "cpp/cpp-pthread/demo12c02-race-cond-data-race.cpp",
    "chars": 758,
    "preview": "/*\nRACE CONDITIONS AND DATA RACES\n*/\n\n\n#include <iostream>\n#include <pthread.h>\n#include <unistd.h>\nusing namespace std;"
  },
  {
    "path": "cpp/cpp-pthread/demo13a-mutex.cpp",
    "chars": 804,
    "preview": "/*\nMUTEXES\n*/\n\n\n#include <iostream>\n#include <unistd.h>\n#include <pthread.h>\nusing namespace std;\n\n\n\npthread_mutex_t mut"
  },
  {
    "path": "cpp/cpp-pthread/demo13b-mutex-trylock.cpp",
    "chars": 2255,
    "preview": "/*\nMUTEXES\nLocking with a nonblocking mutex\n\nUse pthread_mutex_trylock to attempt to lock the mutex pointed to by mutex."
  },
  {
    "path": "cpp/cpp-pthread/demo14-synchronized-block.cpp",
    "chars": 1672,
    "preview": "/*\nSYNCHRONIZED BLOCKS\n\nSynchronized blocks in C++ POSIX threading are not supported by default.\nTo demonstate synchroni"
  },
  {
    "path": "cpp/cpp-pthread/demo15a-deadlock.cpp",
    "chars": 783,
    "preview": "/*\nDEADLOCK\nVersion A\n*/\n\n\n#include <iostream>\n#include <pthread.h>\nusing namespace std;\n\n\n\npthread_mutex_t mut = PTHREA"
  },
  {
    "path": "cpp/cpp-pthread/demo15b-deadlock.cpp",
    "chars": 1367,
    "preview": "/*\nDEADLOCK\nVersion B\n*/\n\n\n#include <iostream>\n#include <unistd.h>\n#include <pthread.h>\nusing namespace std;\n\n\n\npthread_"
  },
  {
    "path": "cpp/cpp-pthread/demo16-monitor.cpp",
    "chars": 1364,
    "preview": "/*\nMONITORS\nImplementation of a monitor for managing a counter\n*/\n\n\n#include <iostream>\n#include <unistd.h>\n#include <pt"
  },
  {
    "path": "cpp/cpp-pthread/demo17a-reentrant-lock.cpp",
    "chars": 852,
    "preview": "/*\nREENTRANT LOCKS (RECURSIVE MUTEXES)\nVersion A: Introduction to reentrant locks\n*/\n\n\n#include <iostream>\n#include <pth"
  },
  {
    "path": "cpp/cpp-pthread/demo17b-reentrant-lock.cpp",
    "chars": 955,
    "preview": "/*\nREENTRANT LOCKS (RECURSIVE MUTEXES)\nVersion B: Solving the problem from version A\n*/\n\n\n#include <iostream>\n#include <"
  },
  {
    "path": "cpp/cpp-pthread/demo17c-reentrant-lock.cpp",
    "chars": 1259,
    "preview": "/*\nREENTRANT LOCKS (RECURSIVE MUTEXES)\nVersion C: A multithreaded app example\n*/\n\n\n#include <iostream>\n#include <unistd."
  },
  {
    "path": "cpp/cpp-pthread/demo18a01-barrier.cpp",
    "chars": 1290,
    "preview": "/*\nBARRIERS AND LATCHES\nVersion A: Cyclic barriers\n*/\n\n\n#include <iostream>\n#include <string>\n#include <tuple>\n#include "
  },
  {
    "path": "cpp/cpp-pthread/demo18a02-barrier.cpp",
    "chars": 1368,
    "preview": "/*\nBARRIERS AND LATCHES\nVersion A: Cyclic barriers\n*/\n\n\n#include <iostream>\n#include <string>\n#include <tuple>\n#include "
  },
  {
    "path": "cpp/cpp-pthread/demo18a03-barrier.cpp",
    "chars": 1428,
    "preview": "/*\nBARRIERS AND LATCHES\nVersion A: Cyclic barriers\n*/\n\n\n#include <iostream>\n#include <string>\n#include <tuple>\n#include "
  },
  {
    "path": "cpp/cpp-pthread/demo18b01-latch.cpp",
    "chars": 1243,
    "preview": "/*\nBARRIERS AND LATCHES\nVersion B: Count-down latches\n\nCount-down latches in C++ POSIX threading are not supported by de"
  },
  {
    "path": "cpp/cpp-pthread/demo18b02-latch.cpp",
    "chars": 1448,
    "preview": "/*\nBARRIERS AND LATCHES\nVersion B: Count-down latches\n\nMain thread waits for 3 child threads to get enough data to progr"
  },
  {
    "path": "cpp/cpp-pthread/demo19-read-write-lock.cpp",
    "chars": 2606,
    "preview": "/*\nREAD-WRITE LOCKS\n\nLock for reading\n    A thread can hold multiple concurrent read locks on the rwlock object\n    (tha"
  },
  {
    "path": "cpp/cpp-pthread/demo20a01-semaphore.cpp",
    "chars": 1212,
    "preview": "/*\nSEMAPHORES\nVersion A: Paper sheets and packages\n*/\n\n\n#include <iostream>\n#include <unistd.h>\n#include <pthread.h>\n#in"
  },
  {
    "path": "cpp/cpp-pthread/demo20a02-semaphore.cpp",
    "chars": 1389,
    "preview": "/*\nSEMAPHORES\nVersion A: Paper sheets and packages\n*/\n\n\n#include <iostream>\n#include <unistd.h>\n#include <pthread.h>\n#in"
  },
  {
    "path": "cpp/cpp-pthread/demo20a03-semaphore-deadlock.cpp",
    "chars": 1427,
    "preview": "/*\nSEMAPHORES\nVersion A: Paper sheets and packages\n*/\n\n\n#include <iostream>\n#include <unistd.h>\n#include <pthread.h>\n#in"
  },
  {
    "path": "cpp/cpp-pthread/demo20b-semaphore.cpp",
    "chars": 1438,
    "preview": "/*\nSEMAPHORES\nVersion B: Tires and chassis\n*/\n\n\n#include <iostream>\n#include <unistd.h>\n#include <pthread.h>\n#include <s"
  },
  {
    "path": "cpp/cpp-pthread/demo21a01-condition-variable.cpp",
    "chars": 970,
    "preview": "/*\nCONDITION VARIABLES\n*/\n\n\n#include <iostream>\n#include <unistd.h>\n#include <pthread.h>\nusing namespace std;\n\n\n\npthread"
  },
  {
    "path": "cpp/cpp-pthread/demo21a02-condition-variable.cpp",
    "chars": 1186,
    "preview": "/*\nCONDITION VARIABLES\n*/\n\n\n#include <iostream>\n#include <unistd.h>\n#include <pthread.h>\nusing namespace std;\n\n\n\npthread"
  },
  {
    "path": "cpp/cpp-pthread/demo21a03-condition-variable.cpp",
    "chars": 1166,
    "preview": "/*\nCONDITION VARIABLES\n*/\n\n\n#include <iostream>\n#include <unistd.h>\n#include <pthread.h>\nusing namespace std;\n\n\n\npthread"
  },
  {
    "path": "cpp/cpp-pthread/demo21b-condition-variable.cpp",
    "chars": 2045,
    "preview": "/*\nCONDITION VARIABLES\n*/\n\n\n#include <iostream>\n#include <pthread.h>\nusing namespace std;\n\n\n\npthread_mutex_t mut = PTHRE"
  },
  {
    "path": "cpp/cpp-pthread/demo22a-blocking-queue.cpp",
    "chars": 1299,
    "preview": "/*\nBLOCKING QUEUES\nVersion A: A slow producer and a fast consumer\n\nBlocking queues in C++ POSIX threading are not suppor"
  },
  {
    "path": "cpp/cpp-pthread/demo22b-blocking-queue.cpp",
    "chars": 1479,
    "preview": "/*\nBLOCKING QUEUES\nVersion B: A fast producer and a slow consumer\n\nBlocking queues in C++ POSIX threading are not suppor"
  },
  {
    "path": "cpp/cpp-pthread/demo23a-thread-local.cpp",
    "chars": 576,
    "preview": "/*\nTHREAD-LOCAL STORAGE\nIntroduction\n\nThe code is specific for gcc.\n*/\n\n\n#include <iostream>\n#include <pthread.h>\nusing "
  },
  {
    "path": "cpp/cpp-pthread/demo23b-thread-local.cpp",
    "chars": 883,
    "preview": "/*\nTHREAD-LOCAL STORAGE\nAvoiding synchronization using thread-local storage\n\nThe code is specific for gcc.\n*/\n\n\n#include"
  },
  {
    "path": "cpp/cpp-pthread/demo24-volatile.cpp",
    "chars": 527,
    "preview": "/*\nTHE VOLATILE KEYWORD\n*/\n\n\n#include <iostream>\n#include <unistd.h>\n#include <pthread.h>\nusing namespace std;\n\n\n\nvolati"
  },
  {
    "path": "cpp/cpp-pthread/demo25a-atomic.c",
    "chars": 619,
    "preview": "/*\nATOMIC ACCESS\n\nIn this demo, I use raw C language (not C++).\n*/\n\n\n#include <stdio.h>\n#include <pthread.h>\n#include <u"
  },
  {
    "path": "cpp/cpp-pthread/demo25b-atomic.c",
    "chars": 702,
    "preview": "/*\nATOMIC ACCESS\n\nIn this demo, I use raw C language (not C++).\n*/\n\n\n#include <stdio.h>\n#include <pthread.h>\n#include <s"
  },
  {
    "path": "cpp/cpp-pthread/demoex-attribute.cpp",
    "chars": 1061,
    "preview": "#include <iostream>\n#include <unistd.h>\n#include <pthread.h>\nusing namespace std;\n\n\n\nvoid* doTask(void* ptrId) {\n    int"
  },
  {
    "path": "cpp/cpp-pthread/demoex-oop.cpp",
    "chars": 1072,
    "preview": "#include <iostream>\n#include <pthread.h>\nusing namespace std;\n\n\n\nclass Task {\nprivate:\n    pthread_t tid;\npublic:\n    in"
  },
  {
    "path": "cpp/cpp-pthread/demoex-signal.cpp",
    "chars": 669,
    "preview": "#include <iostream>\n#include <unistd.h>\n#include <signal.h>\n#include <pthread.h>\nusing namespace std;\n\n\n\nvoid signalHand"
  },
  {
    "path": "cpp/cpp-pthread/exer01a-max-div.cpp",
    "chars": 914,
    "preview": "/*\nMAXIMUM NUMBER OF DIVISORS\n*/\n\n\n#include <iostream>\n#include \"../cpp-std/mylib-time.hpp\"\nusing namespace std;\n\n\n\nint "
  },
  {
    "path": "cpp/cpp-pthread/exer01b-max-div.cpp",
    "chars": 2951,
    "preview": "/*\nMAXIMUM NUMBER OF DIVISORS\n*/\n\n\n#include <iostream>\n#include <vector>\n#include <algorithm>\n#include <pthread.h>\n#incl"
  },
  {
    "path": "cpp/cpp-pthread/exer01c-max-div.cpp",
    "chars": 2972,
    "preview": "/*\nMAXIMUM NUMBER OF DIVISORS\n*/\n\n\n#include <iostream>\n#include <vector>\n#include <algorithm>\n#include <pthread.h>\n#incl"
  },
  {
    "path": "cpp/cpp-pthread/exer02a01-producer-consumer.cpp",
    "chars": 1059,
    "preview": "/*\nTHE PRODUCER-CONSUMER PROBLEM\n\nSOLUTION TYPE A: USING BLOCKING QUEUES\n    Version A01: 1 slow producer, 1 fast consum"
  },
  {
    "path": "cpp/cpp-pthread/exer02a02-producer-consumer.cpp",
    "chars": 1206,
    "preview": "/*\nTHE PRODUCER-CONSUMER PROBLEM\n\nSOLUTION TYPE A: USING BLOCKING QUEUES\n    Version A02: 2 slow producers, 1 fast consu"
  },
  {
    "path": "cpp/cpp-pthread/exer02a03-producer-consumer.cpp",
    "chars": 1450,
    "preview": "/*\nTHE PRODUCER-CONSUMER PROBLEM\n\nSOLUTION TYPE A: USING BLOCKING QUEUES\n    Version A03: 1 slow producer, 2 fast consum"
  },
  {
    "path": "cpp/cpp-pthread/exer02a04-producer-consumer.cpp",
    "chars": 1818,
    "preview": "/*\nTHE PRODUCER-CONSUMER PROBLEM\n\nSOLUTION TYPE A: USING BLOCKING QUEUES\n    Version A04: Multiple fast producers, multi"
  },
  {
    "path": "cpp/cpp-pthread/exer02b01-producer-consumer.cpp",
    "chars": 2002,
    "preview": "/*\nTHE PRODUCER-CONSUMER PROBLEM\n\nSOLUTION TYPE B: USING SEMAPHORES\n    Version B01: 1 slow producer, 1 fast consumer\n*/"
  },
  {
    "path": "cpp/cpp-pthread/exer02b02-producer-consumer.cpp",
    "chars": 2299,
    "preview": "/*\nTHE PRODUCER-CONSUMER PROBLEM\n\nSOLUTION TYPE B: USING SEMAPHORES\n    Version B02: 2 slow producers, 1 fast consumer\n*"
  },
  {
    "path": "cpp/cpp-pthread/exer02b03-producer-consumer.cpp",
    "chars": 2297,
    "preview": "/*\nTHE PRODUCER-CONSUMER PROBLEM\n\nSOLUTION TYPE B: USING SEMAPHORES\n    Version B03: 2 fast producers, 1 slow consumer\n*"
  },
  {
    "path": "cpp/cpp-pthread/exer02b04-producer-consumer.cpp",
    "chars": 2745,
    "preview": "/*\nTHE PRODUCER-CONSUMER PROBLEM\n\nSOLUTION TYPE B: USING SEMAPHORES\n    Version B04: Multiple fast producers, multiple s"
  },
  {
    "path": "cpp/cpp-pthread/exer02c-producer-consumer.cpp",
    "chars": 3640,
    "preview": "/*\nTHE PRODUCER-CONSUMER PROBLEM\n\nSOLUTION TYPE C: USING CONDITION VARIABLES & MONITORS\n    Multiple fast producers, mul"
  },
  {
    "path": "cpp/cpp-pthread/exer03a-readers-writers.cpp",
    "chars": 2827,
    "preview": "/*\nTHE READERS-WRITERS PROBLEM\nSolution for the first readers-writers problem\n*/\n\n\n#include <iostream>\n#include <unistd."
  },
  {
    "path": "cpp/cpp-pthread/exer03b-readers-writers.cpp",
    "chars": 3141,
    "preview": "/*\nTHE READERS-WRITERS PROBLEM\nSolution for the third readers-writers problem\n*/\n\n\n#include <iostream>\n#include <unistd."
  },
  {
    "path": "cpp/cpp-pthread/exer04-dining-philosophers.cpp",
    "chars": 1555,
    "preview": "/*\nTHE DINING PHILOSOPHERS PROBLEM\n*/\n\n\n#include <iostream>\n#include <unistd.h>\n#include <pthread.h>\nusing namespace std"
  },
  {
    "path": "cpp/cpp-pthread/exer05-util.hpp",
    "chars": 568,
    "preview": "#ifndef _EXER05_UTIL_HPP_\n#define _EXER05_UTIL_HPP_\n\n\n\nstruct WorkerScProdArg {\n    double const* u = nullptr;\n    doubl"
  },
  {
    "path": "cpp/cpp-pthread/exer05a-product-matrix-vector.cpp",
    "chars": 1269,
    "preview": "/*\nMATRIX-VECTOR MULTIPLICATION\n*/\n\n\n#include <iostream>\n#include <vector>\n#include <pthread.h>\n#include \"exer05-util.hp"
  },
  {
    "path": "cpp/cpp-pthread/exer05b-product-matrix-matrix.cpp",
    "chars": 2138,
    "preview": "/*\nMATRIX-MATRIX MULTIPLICATION (DOT PRODUCT)\n*/\n\n\n#include <iostream>\n#include <vector>\n#include <pthread.h>\n#include \""
  },
  {
    "path": "cpp/cpp-pthread/exer06a-blocking-queue.cpp",
    "chars": 1800,
    "preview": "/*\nBLOCKING QUEUE IMPLEMENTATION\nVersion A: Synchronous queues\n*/\n\n\n#include <iostream>\n#include <string>\n#include <unis"
  },
  {
    "path": "cpp/cpp-pthread/exer06b01-blocking-queue.cpp",
    "chars": 2494,
    "preview": "/*\nBLOCKING QUEUE IMPLEMENTATION\nVersion B01: General blocking queues\n             Underlying mechanism: Semaphores\n*/\n\n"
  },
  {
    "path": "cpp/cpp-pthread/exer06b02-blocking-queue.cpp",
    "chars": 2751,
    "preview": "/*\nBLOCKING QUEUE IMPLEMENTATION\nVersion B02: General blocking queues\n             Underlying mechanism: Condition varia"
  },
  {
    "path": "cpp/cpp-pthread/exer07a-data-server.cpp",
    "chars": 2276,
    "preview": "/*\nTHE DATA SERVER PROBLEM\nVersion A: Solving the problem using a condition variable\n*/\n\n\n#include <iostream>\n#include <"
  },
  {
    "path": "cpp/cpp-pthread/exer07b-data-server.cpp",
    "chars": 1736,
    "preview": "/*\nTHE DATA SERVER PROBLEM\nVersion B: Solving the problem using a semaphore\n*/\n\n\n#include <iostream>\n#include <string>\n#"
  },
  {
    "path": "cpp/cpp-pthread/exer07c-data-server.cpp",
    "chars": 1729,
    "preview": "/*\nTHE DATA SERVER PROBLEM\nVersion C: Solving the problem using a count-down latch\n*/\n\n\n#include <iostream>\n#include <st"
  },
  {
    "path": "cpp/cpp-pthread/exer07d-data-server.cpp",
    "chars": 1786,
    "preview": "/*\nTHE DATA SERVER PROBLEM\nVersion D: Solving the problem using a blocking queue\n*/\n\n\n#include <iostream>\n#include <stri"
  },
  {
    "path": "cpp/cpp-pthread/exer08-exec-service-itask.hpp",
    "chars": 220,
    "preview": "#ifndef _MY_EXEC_SERVICE_ITASK_HPP_\n#define _MY_EXEC_SERVICE_ITASK_HPP_\n\n\n\n// interface ITask\nclass ITask {\npublic:\n    "
  },
  {
    "path": "cpp/cpp-pthread/exer08-exec-service-main.cpp",
    "chars": 1139,
    "preview": "/*\nEXECUTOR SERVICE & THREAD POOL IMPLEMENTATION\n*/\n\n\n#include <iostream>\n#include <unistd.h>\n#include \"exer08-exec-serv"
  },
  {
    "path": "cpp/cpp-pthread/exer08-exec-service-v0a.hpp",
    "chars": 2025,
    "preview": "/*\nMY EXECUTOR SERVICE\n\nVersion 0A: The easiest executor service\n- It uses a blocking queue as underlying mechanism.\n*/\n"
  },
  {
    "path": "cpp/cpp-pthread/exer08-exec-service-v0b.hpp",
    "chars": 2908,
    "preview": "/*\nMY EXECUTOR SERVICE\n\nVersion 0B: The easiest executor service\n- It uses a blocking queue as underlying mechanism.\n- I"
  },
  {
    "path": "cpp/cpp-pthread/exer08-exec-service-v1a.hpp",
    "chars": 3873,
    "preview": "/*\nMY EXECUTOR SERVICE\n\nVersion 1A: Simple executor service\n- Method \"waitTaskDone\" invokes thread sleeps in loop (which"
  },
  {
    "path": "cpp/cpp-pthread/exer08-exec-service-v1b.hpp",
    "chars": 4626,
    "preview": "/*\nMY EXECUTOR SERVICE\n\nVersion 1A: Simple executor service\n- Method \"waitTaskDone\" consumes CPU (due to bad synchroniza"
  },
  {
    "path": "cpp/cpp-pthread/exer08-exec-service-v2a.hpp",
    "chars": 4731,
    "preview": "/*\nMY EXECUTOR SERVICE\n\nVersion 2A: The executor service storing running tasks\n- Method \"waitTaskDone\" uses a semaphore "
  },
  {
    "path": "cpp/cpp-pthread/exer08-exec-service-v2b.hpp",
    "chars": 4836,
    "preview": "/*\nMY EXECUTOR SERVICE\n\nVersion 2B: The executor service storing running tasks\n- Method \"waitTaskDone\" uses a condition "
  },
  {
    "path": "cpp/cpp-pthread/exerex-countdown-timer-a.cpp",
    "chars": 1597,
    "preview": "/*\nCOUNTDOWN TIMER\n*/\n\n\n#include <iostream>\n#include <unistd.h>\n#include <time.h>\n#include <pthread.h>\nusing namespace s"
  },
  {
    "path": "cpp/cpp-pthread/exerex-countdown-timer-b.cpp",
    "chars": 1023,
    "preview": "/*\nCOUNTDOWN TIMER\n*/\n\n\n#include <iostream>\n#include <unistd.h>\n#include <time.h>\n#include <pthread.h>\nusing namespace s"
  },
  {
    "path": "cpp/cpp-pthread/mylib-blockingqueue.hpp",
    "chars": 3663,
    "preview": "/******************************************************\n*\n* File name:    mylib-blockingqueue.hpp\n*\n* Author:       Name"
  },
  {
    "path": "cpp/cpp-pthread/mylib-execservice.hpp",
    "chars": 4951,
    "preview": "/******************************************************\n*\n* File name:    mylib-execservice.hpp\n*\n* Author:       Name: "
  }
]

// ... and 472 more files (download for full content)

About this extraction

This page contains the full source code of the thanhit95/multi-threading GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 672 files (824.3 KB), approximately 225.7k tokens, and a symbol index with 2095 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!