├── .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-ex-thread-pool-deadlock.zip ├── 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 /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | -------------------------------------------------------------------------------- /cpp/.gitignore: -------------------------------------------------------------------------------- 1 | a 2 | a.out 3 | tmp* 4 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo00.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | INTRODUCTION TO MULTITHREADING 3 | You should try running this app several times and see results. 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | void doTask() { 14 | for (int i = 0; i < 300; ++i) 15 | cout << "B"; 16 | } 17 | 18 | 19 | 20 | int main() { 21 | boost::thread th(&doTask); 22 | 23 | for (int i = 0; i < 300; ++i) 24 | cout << "A"; 25 | 26 | th.join(); 27 | 28 | cout << endl; 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo01a01-hello.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | HELLO WORLD VERSION MULTITHREADING 3 | Version A01: Using functions 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | void doTask() { 14 | cout << "Hello from example thread" << endl; 15 | } 16 | 17 | 18 | 19 | int main() { 20 | boost::thread th(&doTask); 21 | 22 | cout << "Hello from main thread" << endl; 23 | 24 | th.join(); 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo01a02-hello.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | HELLO WORLD VERSION MULTITHREADING 3 | Version A02: Using functions allowing passing 2 arguments 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | void doTask(char const* message, int number) { 14 | cout << message << " " << number << endl; 15 | } 16 | 17 | 18 | 19 | int main() { 20 | boost::thread th(&doTask, "Good day", 19); 21 | th.join(); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo01b-hello-class01.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | HELLO WORLD VERSION MULTITHREADING 3 | Version B: Using class methods 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | 13 | 14 | class Example { 15 | public: 16 | void doTask(string message) { 17 | cout << message << endl; 18 | } 19 | }; 20 | 21 | 22 | 23 | int main() { 24 | Example example; 25 | 26 | boost::thread th(&Example::doTask, &example, "Good day"); 27 | // boost::thread th(boost::bind(&Example::doTask, &example, "Good day")); 28 | 29 | th.join(); 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo01b-hello-class02.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | HELLO WORLD VERSION MULTITHREADING 3 | Version B: Using class methods 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | using namespace std; 12 | 13 | 14 | 15 | class Example { 16 | public: 17 | void run() { 18 | boost::thread th(&Example::doTask, this, "Good day"); 19 | // boost::thread th(boost::bind(&Example::doTask, this, "Good day")); 20 | th.join(); 21 | } 22 | 23 | private: 24 | void doTask(string message) { 25 | cout << message << endl; 26 | } 27 | }; 28 | 29 | 30 | 31 | int main() { 32 | Example example; 33 | example.run(); 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo01b-hello-class03.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | HELLO WORLD VERSION MULTITHREADING 3 | Version B: Using class methods 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | 13 | 14 | class Example { 15 | public: 16 | void run() { 17 | boost::thread th(&Example::doTask, "Good day"); 18 | th.join(); 19 | } 20 | 21 | private: 22 | static void doTask(string message) { 23 | cout << message << endl; 24 | } 25 | }; 26 | 27 | 28 | 29 | int main() { 30 | Example example; 31 | example.run(); 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo01b-hello-functor.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | HELLO WORLD VERSION MULTITHREADING 3 | Version B: Using functors 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | 13 | 14 | class Example { 15 | public: 16 | void operator()(string message) { 17 | cout << message << endl; 18 | } 19 | }; 20 | 21 | 22 | 23 | int main() { 24 | Example example; 25 | 26 | boost::thread th(example, "Good day"); 27 | 28 | th.join(); 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo02-join.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | THREAD JOINS 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | 11 | 12 | void doHeavyTask() { 13 | // Do a heavy task, which takes a little time 14 | for (int i = 0; i < 2000000000; ++i); 15 | 16 | cout << "Done!" << endl; 17 | } 18 | 19 | 20 | 21 | int main() { 22 | boost::thread th(&doHeavyTask); 23 | 24 | th.join(); 25 | 26 | cout << "Good bye!" << endl; 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo03a-pass-arg.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | PASSING ARGUMENTS 3 | Version A: Passing multiple arguments with various data types 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | using namespace std; 12 | 13 | 14 | 15 | struct Point { 16 | int x; 17 | int y; 18 | 19 | Point(int x, int y): x(x), y(y) { } 20 | }; 21 | 22 | 23 | 24 | void doTask(int a, double b, string c, char const* d, Point e) { 25 | char buffer[50] = { 0 }; 26 | std::sprintf(buffer, "%d %.1f %s %s (%d %d)", a, b, c.data(), d, e.x, e.y); 27 | cout << buffer << endl; 28 | } 29 | 30 | 31 | 32 | int main() { 33 | boost::thread thFoo(&doTask, 1, 2, "red", "red", Point(0, 0)); 34 | boost::thread thBar(&doTask, 3, 4, "blue", "blue", Point(9, 9)); 35 | 36 | thFoo.join(); 37 | thBar.join(); 38 | 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo03b-pass-arg.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | PASSING ARGUMENTS 3 | Version B: Passing constant references 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | 13 | 14 | void doTask(const string& msg) { 15 | cout << msg << endl; 16 | } 17 | 18 | void doTask(const string& msg) { 19 | cout << msg << endl; 20 | } 21 | 22 | 23 | 24 | int main() { 25 | boost::thread thFoo(&doTask, "foo"); 26 | boost::thread thBar(&doTask, "bar"); 27 | 28 | thFoo.join(); 29 | thBar.join(); 30 | 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo03c-pass-arg.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | PASSING ARGUMENTS 3 | Version C: Passing normal references 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | using namespace std; 12 | 13 | 14 | 15 | void doTask(string& msg) { 16 | cout << msg << endl; 17 | } 18 | 19 | 20 | 21 | int main() { 22 | string a = "lorem ipsum"; 23 | string b = "dolor amet"; 24 | 25 | // We should use boost:ref to pass references 26 | boost::thread thFoo(&doTask, boost::ref(a)); 27 | boost::thread thBar(&doTask, boost::ref(b)); 28 | 29 | // boost::thread thFoo(&doTask, a); 30 | // boost::thread thBar(&doTask, b); 31 | 32 | thFoo.join(); 33 | thBar.join(); 34 | 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo04a-sleep.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SLEEP 3 | Version A: Sleep for a specific duration 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | using namespace std; 12 | 13 | 14 | 15 | void doTask(string name) { 16 | cout << name << " is sleeping" << endl; 17 | boost::this_thread::sleep_for(boost::chrono::seconds(3)); 18 | cout << name << " wakes up" << endl; 19 | } 20 | 21 | 22 | 23 | int main() { 24 | boost::thread thFoo(&doTask, "foo"); 25 | 26 | thFoo.join(); 27 | 28 | cout << "Good bye" << endl; 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo05-id.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | GETTING THREAD'S ID 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | void doTask() { 14 | boost::this_thread::sleep_for(boost::chrono::seconds(2)); 15 | cout << boost::this_thread::get_id() << endl; 16 | } 17 | 18 | 19 | 20 | int main() { 21 | boost::thread thFoo(&doTask); 22 | boost::thread thBar(&doTask); 23 | 24 | cout << "foo's id: " << thFoo.get_id() << endl; 25 | cout << "bar's id: " << thBar.get_id() << endl; 26 | 27 | thFoo.join(); 28 | thBar.join(); 29 | 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo06a-list-threads.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | LIST OF MULTIPLE THREADS 3 | Version A: Using standard arrays 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | void doTask(int index) { 14 | cout << index; 15 | } 16 | 17 | 18 | 19 | int main() { 20 | const int NUM_THREADS = 5; 21 | 22 | boost::thread lstTh[NUM_THREADS]; 23 | 24 | for (int i = 0; i < NUM_THREADS; ++i) { 25 | lstTh[i] = boost::thread(&doTask, i); 26 | } 27 | 28 | for (int i = 0; i < NUM_THREADS; ++i) { 29 | lstTh[i].join(); 30 | } 31 | 32 | cout << endl; 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo06b-list-threads.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | LIST OF MULTIPLE THREADS 3 | Version B: Using the std::vector 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | using namespace std; 12 | 13 | 14 | 15 | typedef boost::shared_ptr threadptr; 16 | 17 | 18 | 19 | void doTask(int index) { 20 | cout << index; 21 | } 22 | 23 | 24 | 25 | int main() { 26 | const int NUM_THREADS = 5; 27 | 28 | vector lstTh; 29 | 30 | for (int i = 0; i < NUM_THREADS; ++i) { 31 | threadptr ptr = boost::make_shared(&doTask, i); 32 | lstTh.push_back(ptr); 33 | } 34 | 35 | for (int i = 0; i < lstTh.size(); ++i) { 36 | lstTh[i]->join(); 37 | } 38 | 39 | cout << endl; 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo06c-list-threads.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | LIST OF MULTIPLE THREADS 3 | Version C: Using the boost::thread_group 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | 13 | 14 | void doTask(int index) { 15 | cout << index; 16 | } 17 | 18 | 19 | 20 | int main() { 21 | const int NUM_THREADS = 5; 22 | 23 | boost::thread_group lstTh; 24 | 25 | for (int i = 0; i < NUM_THREADS; ++i) { 26 | lstTh.add_thread(new boost::thread(&doTask, i)); 27 | // lstTh.create_thread(boost::bind(&doTask, i)); 28 | } 29 | 30 | lstTh.join_all(); 31 | 32 | cout << endl; 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo07-terminate.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | FORCING A THREAD TO TERMINATE (i.e. killing the thread) 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | volatile bool isRunning; 14 | 15 | 16 | 17 | void doTask() { 18 | while (isRunning) { 19 | cout << "Running..." << endl; 20 | boost::this_thread::sleep_for(boost::chrono::seconds(2)); 21 | } 22 | } 23 | 24 | 25 | 26 | int main() { 27 | isRunning = true; 28 | boost::thread th(&doTask); 29 | 30 | boost::this_thread::sleep_for(boost::chrono::seconds(6)); 31 | isRunning = false; 32 | 33 | th.join(); 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo08-return-value.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | GETTING RETURNED VALUES FROM THREADS 3 | Using pointers or references (traditional way) 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | 13 | 14 | void doubleValue(int arg, int* res) { 15 | (*res) = arg * 2; 16 | } 17 | 18 | 19 | 20 | void squareValue(int arg, int& res) { 21 | res = arg * arg; 22 | } 23 | 24 | 25 | 26 | int main() { 27 | int result[3]; 28 | 29 | boost::thread thFoo(&doubleValue, 5, &result[0]); 30 | boost::thread thBar(&doubleValue, 80, &result[1]); 31 | boost::thread thEgg(&squareValue, 7, boost::ref(result[2])); 32 | 33 | thFoo.join(); 34 | thBar.join(); 35 | thEgg.join(); 36 | 37 | cout << result[0] << endl; 38 | cout << result[1] << endl; 39 | cout << result[2] << endl; 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo09-detach.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | THREAD DETACHING 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | void foo() { 14 | cout << "foo is starting..." << endl; 15 | 16 | boost::this_thread::sleep_for(boost::chrono::seconds(2)); 17 | 18 | cout << "foo is exiting..." << endl; 19 | } 20 | 21 | 22 | 23 | int main() { 24 | boost::thread thFoo(&foo); 25 | thFoo.detach(); 26 | 27 | 28 | // If I comment this statement, 29 | // thFoo will be forced into terminating with main thread 30 | boost::this_thread::sleep_for(boost::chrono::seconds(3)); 31 | 32 | 33 | cout << "Main thread is exiting" << endl; 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo10-yield.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | THREAD YIELDING 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | #include "mylib-time.hpp" 10 | using namespace std; 11 | 12 | 13 | 14 | typedef boost::chrono::microseconds chrmicro; 15 | typedef boost::chrono::steady_clock::time_point time_point; 16 | typedef mylib::HiResClock hrclock; 17 | 18 | 19 | 20 | void littleSleep(int us) { 21 | time_point tpStart = hrclock::now(); 22 | time_point tpEnd = tpStart + chrmicro(us); 23 | 24 | do { 25 | boost::this_thread::yield(); 26 | } 27 | while (hrclock::now() < tpEnd); 28 | } 29 | 30 | 31 | 32 | int main() { 33 | time_point tpStartMeasure = hrclock::now(); 34 | 35 | littleSleep(130); 36 | 37 | chrmicro timeElapsed = hrclock::getTimeSpan(tpStartMeasure); 38 | 39 | cout << "Elapsed time: " << timeElapsed.count() << " microseonds" << endl; 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo11a-exec-service.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | EXECUTOR SERVICES AND THREAD POOLS 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | 13 | 14 | void doTask() { 15 | cout << "Hello the Executor Service" << endl; 16 | } 17 | 18 | 19 | 20 | class MyFunctor { 21 | public: 22 | void operator()() { 23 | cout << "Hello Multithreading" << endl; 24 | } 25 | }; 26 | 27 | 28 | 29 | int main() { 30 | // INIT THE EXECUTOR SERVICE WITH 2 THREADS 31 | boost::asio::thread_pool pool(2); 32 | 33 | 34 | // SUBMIT 35 | boost::asio::post(pool, boost::bind(&doTask /* , argument1, argument2,... */)); 36 | boost::asio::post(pool, MyFunctor()); 37 | 38 | 39 | // WAIT FOR THE COMPLETION OF ALL TASKS AND SHUTDOWN EXECUTOR SERVICE 40 | pool.join(); 41 | pool.stop(); 42 | 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo11b-exec-service.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | EXECUTOR SERVICES AND THREAD POOLS 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | using namespace std; 12 | 13 | 14 | 15 | void doTask(char id) { 16 | cout << "Task " << id << " is starting" << endl; 17 | boost::this_thread::sleep_for(boost::chrono::seconds(3)); 18 | cout << "Task " << id << " is completed" << endl; 19 | } 20 | 21 | 22 | 23 | int main() { 24 | const int NUM_THREADS = 2; 25 | const int NUM_TASKS = 5; 26 | 27 | boost::asio::thread_pool pool(NUM_THREADS); 28 | 29 | for (int i = 0; i < NUM_TASKS; ++i) { 30 | boost::asio::post(pool, boost::bind(&doTask, 'A' + i)); 31 | } 32 | 33 | cout << "All tasks are submitted" << endl; 34 | 35 | pool.join(); 36 | cout << "All tasks are completed" << endl; 37 | 38 | pool.stop(); 39 | 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo12a-race-condition.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | RACE CONDITIONS 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | void doTask(int index) { 14 | boost::this_thread::sleep_for(boost::chrono::seconds(1)); 15 | cout << index; 16 | } 17 | 18 | 19 | 20 | int main() { 21 | const int NUM_THREADS = 4; 22 | boost::thread_group lstTh; 23 | 24 | for (int i = 0; i < NUM_THREADS; ++i) { 25 | lstTh.add_thread(new boost::thread(&doTask, i)); 26 | } 27 | 28 | lstTh.join_all(); 29 | 30 | cout << endl; 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo12b01-data-race-single.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | DATA RACES 3 | Version 01: Without multithreading 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | 13 | 14 | int getResult(int N) { 15 | vector a; 16 | a.resize(N + 1, false); 17 | 18 | for (int i = 1; i <= N; ++i) 19 | if (0 == i % 2 || 0 == i % 3) 20 | a[i] = true; 21 | 22 | // result = sum of a (i.e. counting number of true values in a) 23 | int result = std::accumulate(a.begin(), a.end(), 0); 24 | return result; 25 | } 26 | 27 | 28 | 29 | int main() { 30 | const int N = 8; 31 | 32 | int result = getResult(N); 33 | 34 | cout << "Number of integers that are divisible by 2 or 3 is: " << result << endl; 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo12c01-race-cond-data-race.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | RACE CONDITIONS AND DATA RACES 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | int counter = 0; 14 | 15 | 16 | 17 | void increaseCounter() { 18 | boost::this_thread::sleep_for(boost::chrono::seconds(1)); 19 | 20 | for (int i = 0; i < 1000; ++i) { 21 | counter += 1; 22 | } 23 | } 24 | 25 | 26 | 27 | int main() { 28 | const int NUM_THREADS = 16; 29 | boost::thread_group lstTh; 30 | 31 | for (int i = 0; i < NUM_THREADS; ++i) { 32 | lstTh.add_thread(new boost::thread(&increaseCounter)); 33 | } 34 | 35 | lstTh.join_all(); 36 | 37 | cout << "counter = " << counter << endl; 38 | // We are NOT sure that counter = 16000 39 | 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo13a-mutex.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | MUTEXES 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | boost::mutex mut; 14 | int counter = 0; 15 | 16 | 17 | 18 | void doTask() { 19 | boost::this_thread::sleep_for(boost::chrono::seconds(1)); 20 | 21 | mut.lock(); 22 | 23 | for (int i = 0; i < 1000; ++i) 24 | ++counter; 25 | 26 | mut.unlock(); 27 | } 28 | 29 | 30 | 31 | int main() { 32 | const int NUM_THREADS = 16; 33 | boost::thread_group lstTh; 34 | 35 | for (int i = 0; i < NUM_THREADS; ++i) { 36 | lstTh.add_thread(new boost::thread(&doTask)); 37 | } 38 | 39 | lstTh.join_all(); 40 | 41 | cout << "counter = " << counter << endl; 42 | // We are sure that counter = 16000 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo13b01-mutex.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | MUTEXES 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | boost::mutex mut; 14 | int counter = 0; 15 | 16 | 17 | 18 | void doTask() { 19 | boost::this_thread::sleep_for(boost::chrono::seconds(1)); 20 | 21 | boost::lock_guard lk(mut); 22 | 23 | for (int i = 0; i < 1000; ++i) 24 | ++counter; 25 | 26 | // Once function exits, then destructor of lk object will be called. 27 | // In destructor it unlocks the mutex. 28 | } 29 | 30 | 31 | 32 | int main() { 33 | const int NUM_THREADS = 16; 34 | boost::thread_group lstTh; 35 | 36 | for (int i = 0; i < NUM_THREADS; ++i) { 37 | lstTh.add_thread(new boost::thread(&doTask)); 38 | } 39 | 40 | lstTh.join_all(); 41 | 42 | cout << "counter = " << counter << endl; 43 | // We are sure that counter = 16000 44 | 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo13c-mutex-trylock.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | MUTEXES 3 | Locking with a nonblocking mutex 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | 13 | 14 | boost::mutex mut; 15 | int counter = 0; 16 | 17 | 18 | 19 | void doTask() { 20 | boost::this_thread::sleep_for(boost::chrono::seconds(1)); 21 | 22 | if (false == mut.try_lock()) { 23 | return; 24 | } 25 | 26 | for (int i = 0; i < 10000; ++i) 27 | ++counter; 28 | 29 | mut.unlock(); 30 | } 31 | 32 | 33 | 34 | int main() { 35 | const int NUM_THREADS = 3; 36 | boost::thread_group lstTh; 37 | 38 | for (int i = 0; i < NUM_THREADS; ++i) { 39 | lstTh.add_thread(new boost::thread(&doTask)); 40 | } 41 | 42 | lstTh.join_all(); 43 | 44 | cout << "counter = " << counter << endl; 45 | // counter can be 10000, 20000 or 30000 46 | 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo15a-deadlock.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | DEADLOCK 3 | Version A 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | 13 | 14 | boost::mutex mut; 15 | 16 | 17 | 18 | void doTask(std::string name) { 19 | mut.lock(); 20 | 21 | cout << name << " acquired resource" << endl; 22 | 23 | // mut.unlock(); // Forget this statement ==> deadlock 24 | } 25 | 26 | 27 | 28 | int main() { 29 | boost::thread thFoo(&doTask, "foo"); 30 | boost::thread thBar(&doTask, "bar"); 31 | 32 | thFoo.join(); 33 | thBar.join(); 34 | 35 | cout << "You will never see this statement due to deadlock!" << endl; 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo17a-reentrant-lock.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | REENTRANT LOCKS (RECURSIVE MUTEXES) 3 | Version A: Introduction to reentrant locks 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | boost::mutex mut; 14 | 15 | 16 | 17 | void doTask() { 18 | mut.lock(); 19 | cout << "First time acquiring the resource" << endl; 20 | 21 | mut.lock(); 22 | cout << "Second time acquiring the resource" << endl; 23 | 24 | mut.unlock(); 25 | mut.unlock(); 26 | } 27 | 28 | 29 | 30 | int main() { 31 | boost::thread th(&doTask); 32 | /* 33 | The thread th shall meet deadlock. 34 | So, you will never get output "Second time the acquiring resource". 35 | */ 36 | th.join(); 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo17b-reentrant-lock.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | REENTRANT LOCKS (RECURSIVE MUTEXES) 3 | Version B: Solving the problem from version A 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | boost::recursive_mutex mut; 14 | 15 | 16 | 17 | void doTask() { 18 | mut.lock(); 19 | cout << "First time acquiring the resource" << endl; 20 | 21 | mut.lock(); 22 | cout << "Second time acquiring the resource" << endl; 23 | 24 | mut.unlock(); 25 | mut.unlock(); 26 | } 27 | 28 | 29 | 30 | void doTaskUsingSyncBlock() { 31 | typedef boost::unique_lock uniquelk; 32 | 33 | uniquelk(mut); 34 | cout << "First time acquiring the resource" << endl; 35 | 36 | { 37 | uniquelk(mut); 38 | cout << "Second time acquiring the resource" << endl; 39 | } 40 | } 41 | 42 | 43 | 44 | int main() { 45 | boost::thread th(&doTask); 46 | th.join(); 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo21a01-condition-variable.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | CONDITION VARIABLES 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | boost::mutex mut; 14 | boost::condition_variable conditionVar; 15 | 16 | 17 | 18 | void foo() { 19 | cout << "foo is waiting..." << endl; 20 | 21 | boost::unique_lock mutLock(mut); 22 | conditionVar.wait(mutLock); 23 | 24 | cout << "foo resumed" << endl; 25 | } 26 | 27 | 28 | 29 | void bar() { 30 | boost::this_thread::sleep_for(boost::chrono::seconds(3)); 31 | conditionVar.notify_one(); 32 | } 33 | 34 | 35 | 36 | int main() { 37 | boost::thread thFoo(&foo); 38 | boost::thread thBar(&bar); 39 | 40 | thFoo.join(); 41 | thBar.join(); 42 | 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo21a03-condition-variable.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | CONDITION VARIABLES 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | boost::mutex mut; 14 | boost::condition_variable conditionVar; 15 | 16 | const int NUM_TH_FOO = 3; 17 | 18 | 19 | 20 | void foo() { 21 | cout << "foo is waiting..." << endl; 22 | 23 | boost::unique_lock mutLock(mut); 24 | conditionVar.wait(mutLock); 25 | 26 | cout << "foo resumed" << endl; 27 | } 28 | 29 | 30 | 31 | void bar() { 32 | boost::this_thread::sleep_for(boost::chrono::seconds(3)); 33 | // Notify all waiting threads 34 | conditionVar.notify_all(); 35 | } 36 | 37 | 38 | 39 | int main() { 40 | boost::thread_group lstThFoo; 41 | 42 | for (int i = 0; i < NUM_TH_FOO; ++i) { 43 | lstThFoo.add_thread(new boost::thread(&foo)); 44 | } 45 | 46 | boost::thread thBar(&bar); 47 | 48 | lstThFoo.join_all(); 49 | thBar.join(); 50 | 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo23a-thread-local.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | THREAD-LOCAL STORAGE 3 | Introduction 4 | The basic way to use thread-local storage 5 | */ 6 | 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | using namespace std; 13 | 14 | 15 | 16 | boost::thread_specific_ptr value; 17 | 18 | 19 | 20 | void printLocalValue() { 21 | cout << (*value.get()) << endl; 22 | } 23 | 24 | 25 | 26 | void doTaskApple() { 27 | value.reset(new string("APPLE")); 28 | boost::this_thread::sleep_for(boost::chrono::seconds(2)); 29 | printLocalValue(); 30 | } 31 | 32 | 33 | 34 | void doTaskBanana() { 35 | value.reset(new string("BANANA")); 36 | boost::this_thread::sleep_for(boost::chrono::seconds(2)); 37 | printLocalValue(); 38 | } 39 | 40 | 41 | 42 | int main() { 43 | boost::thread thApple(&doTaskApple); 44 | boost::thread thBanana(&doTaskBanana); 45 | 46 | thApple.join(); 47 | thBanana.join(); 48 | 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo24-volatile.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | THE VOLATILE KEYWORD 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | volatile bool isRunning; 14 | 15 | 16 | 17 | void doTask() { 18 | while (isRunning) { 19 | cout << "Running..." << endl; 20 | boost::this_thread::sleep_for(boost::chrono::seconds(2)); 21 | } 22 | } 23 | 24 | 25 | 26 | int main() { 27 | isRunning = true; 28 | boost::thread th(&doTask); 29 | 30 | boost::this_thread::sleep_for(boost::chrono::seconds(6)); 31 | isRunning = false; 32 | 33 | th.join(); 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo25a-atomic.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ATOMIC ACCESS 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | volatile int counter = 0; 14 | 15 | 16 | 17 | void doTask() { 18 | boost::this_thread::sleep_for(boost::chrono::seconds(1)); 19 | counter += 1; 20 | } 21 | 22 | 23 | 24 | int main() { 25 | counter = 0; 26 | 27 | boost::thread_group lstTh; 28 | 29 | for (int i = 0; i < 1000; ++i) { 30 | lstTh.add_thread(new boost::thread(&doTask)); 31 | } 32 | 33 | lstTh.join_all(); 34 | 35 | // Unpredictable result 36 | cout << "counter = " << counter << endl; 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /cpp/cpp-boost/demo25b-atomic.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ATOMIC ACCESS 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | // boost::atomic counter; 14 | boost::atomic_int32_t counter; 15 | 16 | 17 | 18 | void doTask() { 19 | boost::this_thread::sleep_for(boost::chrono::seconds(1)); 20 | counter += 1; 21 | } 22 | 23 | 24 | 25 | int main() { 26 | counter = 0; 27 | 28 | boost::thread_group lstTh; 29 | 30 | for (int i = 0; i < 1000; ++i) { 31 | lstTh.add_thread(new boost::thread(&doTask)); 32 | } 33 | 34 | lstTh.join_all(); 35 | 36 | // counter = 1000 37 | cout << "counter = " << counter << endl; 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /cpp/cpp-boost/exer05-util.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _EXER05_UTIL_HPP_ 2 | #define _EXER05_UTIL_HPP_ 3 | 4 | 5 | 6 | void getScalarProduct(double const* u, double const* v, int sizeVector, double* res) { 7 | double sum = 0; 8 | 9 | for (int i = sizeVector - 1; i >= 0; --i) { 10 | sum += u[i] * v[i]; 11 | } 12 | 13 | (*res) = sum; 14 | } 15 | 16 | 17 | 18 | #endif // _EXER05_UTIL_HPP_ 19 | -------------------------------------------------------------------------------- /cpp/cpp-boost/exer08-exec-service-itask.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _MY_EXEC_SERVICE_ITASK_HPP_ 2 | #define _MY_EXEC_SERVICE_ITASK_HPP_ 3 | 4 | 5 | 6 | // interface ITask 7 | class ITask { 8 | public: 9 | virtual ~ITask() { } 10 | virtual void run() = 0; 11 | }; 12 | 13 | 14 | 15 | #endif // _MY_EXEC_SERVICE_ITASK_HPP_ 16 | -------------------------------------------------------------------------------- /cpp/cpp-pthread/demo00.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | INTRODUCTION TO MULTITHREADING 3 | You should try running this app several times and see results. 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | void* doTask(void*) { 14 | for (int i = 0; i < 300; ++i) 15 | cout << "B"; 16 | 17 | pthread_exit(nullptr); 18 | return nullptr; 19 | } 20 | 21 | 22 | 23 | int main() { 24 | pthread_t tid; 25 | int ret = 0; 26 | 27 | ret = pthread_create(&tid, nullptr, &doTask, nullptr); 28 | 29 | for (int i = 0; i < 300; ++i) 30 | cout << "A"; 31 | 32 | ret = pthread_join(tid, nullptr); 33 | 34 | cout << endl; 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /cpp/cpp-pthread/demo01-hello.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | HELLO WORLD VERSION MULTITHREADING 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | 11 | 12 | void* doTask(void*) { 13 | cout << "Hello from example thread" << endl; 14 | 15 | pthread_exit(nullptr); 16 | return nullptr; 17 | } 18 | 19 | 20 | 21 | int main() { 22 | pthread_t tid; 23 | int ret = 0; 24 | 25 | ret = pthread_create(&tid, nullptr, &doTask, nullptr); 26 | 27 | /* 28 | if (ret) { 29 | cerr << "Error: Unable to create thread " << ret << endl; 30 | return 1; 31 | } 32 | */ 33 | 34 | ret = pthread_join(tid, nullptr); 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /cpp/cpp-pthread/demo02-join.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | THREAD JOINS 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | 11 | 12 | void* doHeavyTask(void*) { 13 | // Do a heavy task, which takes a little time 14 | for (int i = 0; i < 2000000000; ++i); 15 | 16 | cout << "Done!" << endl; 17 | 18 | pthread_exit(nullptr); 19 | return nullptr; 20 | } 21 | 22 | 23 | 24 | int main() { 25 | pthread_t tid; 26 | int ret = 0; 27 | 28 | ret = pthread_create(&tid, nullptr, &doHeavyTask, nullptr); 29 | 30 | ret = pthread_join(tid, nullptr); 31 | 32 | cout << "Good bye!" << endl; 33 | 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /cpp/cpp-pthread/demo03a01-pass-arg.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | PASSING ARGUMENTS 3 | Version A01: The problem 4 | 5 | The id in statement "hello pthread with id..." might be DUPLICATED!!! 6 | Reason: Passing the address of variable i, 7 | so that all threads use a same value of i. 8 | */ 9 | 10 | 11 | #include 12 | #include 13 | using namespace std; 14 | 15 | 16 | 17 | void* doTask(void* ptrId) { 18 | int id = *(int*)ptrId; 19 | 20 | cout << "Hello pthread with id = " << id << endl; 21 | 22 | pthread_exit(nullptr); 23 | return nullptr; 24 | } 25 | 26 | 27 | 28 | int main() { 29 | pthread_t lstTid[2]; 30 | int ret = 0; 31 | 32 | for (int i = 0; i < 2; ++i) 33 | ret = pthread_create(&lstTid[i], nullptr, &doTask, &i); 34 | 35 | for (int i = 0; i < 2; ++i) 36 | ret = pthread_join(lstTid[i], nullptr); 37 | 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /cpp/cpp-pthread/demo03a02-pass-arg.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | PASSING ARGUMENTS 3 | Version A02: Solving the problem 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | void* doTask(void* ptrId) { 14 | int id = *(int*)ptrId; 15 | 16 | cout << "Hello pthread with id = " << id << endl; 17 | 18 | pthread_exit(nullptr); 19 | return nullptr; 20 | } 21 | 22 | 23 | 24 | int main() { 25 | pthread_t lstTid[2]; 26 | int lstArg[2]; 27 | int ret = 0; 28 | 29 | for (int i = 0; i < 2; ++i) { 30 | lstArg[i] = i + 1; 31 | ret = pthread_create(&lstTid[i], nullptr, &doTask, &lstArg[i]); 32 | } 33 | 34 | for (int i = 0; i < 2; ++i) 35 | ret = pthread_join(lstTid[i], nullptr); 36 | 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /cpp/cpp-pthread/demo03b01-pass-arg.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | PASSING MULTIPLE ARGUMENTS 3 | Solution 01: Creating a custom struct 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | 13 | 14 | struct ThreadArg { 15 | int x; 16 | double y; 17 | string z; 18 | }; 19 | 20 | 21 | 22 | void* doTask(void* argVoid) { 23 | auto arg = (ThreadArg*) argVoid; 24 | 25 | cout << arg->x << endl; 26 | cout << arg->y << endl; 27 | cout << arg->z << endl; 28 | 29 | pthread_exit(nullptr); 30 | return nullptr; 31 | } 32 | 33 | 34 | 35 | int main() { 36 | pthread_t tid; 37 | ThreadArg arg; 38 | int ret = 0; 39 | 40 | arg.x = 10; 41 | arg.y = -2.4; 42 | arg.z = "lorem ipsum"; 43 | 44 | ret = pthread_create(&tid, nullptr, &doTask, &arg); 45 | ret = pthread_join(tid, nullptr); 46 | 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /cpp/cpp-pthread/demo03b02-pass-arg.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | PASSING MULTIPLE ARGUMENTS 3 | Solution 02: Using std::tuple 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | using namespace std; 12 | 13 | 14 | 15 | void* doTask(void* argVoid) { 16 | auto arg = * (tuple *) argVoid; 17 | 18 | cout << std::get<0>(arg) << endl; 19 | cout << std::get<1>(arg) << endl; 20 | cout << std::get<2>(arg) << endl; 21 | 22 | pthread_exit(nullptr); 23 | return nullptr; 24 | } 25 | 26 | 27 | 28 | int main() { 29 | pthread_t tid; 30 | tuple arg; 31 | int ret = 0; 32 | 33 | // arg = std::make_tuple( 10, -2.4, "lorem ipsum" ); 34 | arg = { 10, -2.4, "lorem ipsum" }; 35 | 36 | ret = pthread_create(&tid, nullptr, &doTask, &arg); 37 | ret = pthread_join(tid, nullptr); 38 | 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /cpp/cpp-pthread/demo04-sleep.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SLEEP 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | void* doTask(void* arg) { 14 | auto name = (const char*) arg; 15 | 16 | cout << name << " is sleeping" << endl; 17 | sleep(2); 18 | cout << name << " wakes up" << endl; 19 | 20 | pthread_exit(nullptr); 21 | return nullptr; 22 | } 23 | 24 | 25 | 26 | int main() { 27 | pthread_t tid; 28 | int ret = 0; 29 | 30 | ret = pthread_create(&tid, nullptr, &doTask, (void*)"foo"); 31 | 32 | ret = pthread_join(tid, nullptr); 33 | 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /cpp/cpp-pthread/demo05-id.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | GETTING THREAD'S ID 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | void* doTask(void*) { 14 | sleep(2); 15 | cout << pthread_self() << endl; 16 | 17 | pthread_exit(nullptr); 18 | return nullptr; 19 | } 20 | 21 | 22 | 23 | int main() { 24 | pthread_t tidFoo, tidBar; 25 | int ret = 0; 26 | 27 | ret = pthread_create(&tidFoo, nullptr, &doTask, nullptr); 28 | ret = pthread_create(&tidBar, nullptr, &doTask, nullptr); 29 | 30 | cout << "foo's id = " << tidFoo << endl; 31 | cout << "bar's id = " << tidBar << endl; 32 | 33 | ret = pthread_join(tidFoo, nullptr); 34 | ret = pthread_join(tidBar, nullptr); 35 | 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /cpp/cpp-pthread/demo06a-list-threads.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | LIST OF MULTIPLE THREADS 3 | Version A: Using standard arrays 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | void* doTask(void* arg) { 14 | auto index = *(int*) arg; 15 | cout << index; 16 | 17 | pthread_exit(nullptr); 18 | return nullptr; 19 | } 20 | 21 | 22 | 23 | int main() { 24 | constexpr int NUM_THREADS = 5; 25 | 26 | pthread_t lstTid[NUM_THREADS]; 27 | int lstArg[NUM_THREADS]; 28 | 29 | int ret = 0; 30 | 31 | 32 | for (int i = 0; i < NUM_THREADS; ++i) { 33 | lstArg[i] = i; 34 | ret = pthread_create(&lstTid[i], nullptr, &doTask, &lstArg[i]); 35 | } 36 | 37 | for (auto&& tid : lstTid) { 38 | ret = pthread_join(tid, nullptr); 39 | } 40 | 41 | 42 | cout << endl; 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /cpp/cpp-pthread/demo06b-list-threads.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | LIST OF MULTIPLE THREADS 3 | Version B: Using the std::vector 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | 13 | 14 | void* doTask(void* arg) { 15 | auto index = *(int*) arg; 16 | cout << index; 17 | 18 | pthread_exit(nullptr); 19 | return nullptr; 20 | } 21 | 22 | 23 | 24 | int main() { 25 | constexpr int NUM_THREADS = 5; 26 | 27 | vector lstTid(NUM_THREADS); 28 | vector lstArg(NUM_THREADS); 29 | 30 | int ret = 0; 31 | 32 | 33 | for (int i = 0; i < NUM_THREADS; ++i) { 34 | lstArg[i] = i; 35 | ret = pthread_create(&lstTid[i], nullptr, &doTask, &lstArg[i]); 36 | } 37 | 38 | for (auto&& tid : lstTid) { 39 | ret = pthread_join(tid, nullptr); 40 | } 41 | 42 | 43 | cout << endl; 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /cpp/cpp-pthread/demo07a-terminate.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | FORCING A THREAD TO TERMINATE (i.e. killing the thread) 3 | Version A: Using the flag 'isRunning' 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | 13 | 14 | volatile bool isRunning; 15 | 16 | 17 | 18 | void* doTask(void*) { 19 | while (isRunning) { 20 | cout << "Running..." << endl; 21 | sleep(2); 22 | } 23 | 24 | pthread_exit(nullptr); 25 | return nullptr; 26 | } 27 | 28 | 29 | 30 | int main() { 31 | pthread_t tid; 32 | int ret = 0; 33 | 34 | isRunning = true; 35 | ret = pthread_create(&tid, nullptr, &doTask, nullptr); 36 | 37 | sleep(6); 38 | isRunning = false; 39 | 40 | ret = pthread_join(tid, nullptr); 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /cpp/cpp-pthread/demo07b-terminate.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | FORCING A THREAD TO TERMINATE (i.e. killing the thread) 3 | Version B: Using pthread_cancel 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | 13 | 14 | void* doTask(void*) { 15 | while (1) { 16 | cout << "Running..." << endl; 17 | sleep(1); 18 | } 19 | 20 | pthread_exit(nullptr); 21 | return nullptr; 22 | } 23 | 24 | 25 | 26 | int main() { 27 | pthread_t tid; 28 | int ret = 0; 29 | 30 | ret = pthread_create(&tid, nullptr, &doTask, nullptr); 31 | 32 | sleep(3); 33 | 34 | ret = pthread_cancel(tid); 35 | 36 | ret = pthread_join(tid, nullptr); 37 | 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /cpp/cpp-pthread/demo08a-return-value.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | GETTING RETURNED VALUES FROM THREADS 3 | Version A: Values returned via pointers passed from arguments 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | struct ThreadArg { 14 | int value; 15 | int *res; 16 | }; 17 | 18 | 19 | 20 | void* doubleValue(void* argVoid) { 21 | auto arg = (ThreadArg*) argVoid; 22 | 23 | *(arg->res) = arg->value * 2; 24 | 25 | pthread_exit(nullptr); 26 | return nullptr; 27 | } 28 | 29 | 30 | 31 | int main() { 32 | pthread_t tid; 33 | int result; 34 | ThreadArg arg; 35 | int ret = 0; 36 | 37 | arg = { 80, &result }; 38 | 39 | ret = pthread_create(&tid, nullptr, &doubleValue, &arg); 40 | ret = pthread_join(tid, nullptr); 41 | 42 | cout << result << endl; 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /cpp/cpp-pthread/demo08b-return-value.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | GETTING RETURNED VALUES FROM THREADS 3 | Version B: Values returned via pthread_exit 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | void* doubleValue(void* arg) { 14 | auto value = *(int*) arg; 15 | 16 | int *result = new int; 17 | *result = value * 2; 18 | 19 | pthread_exit((void*)result); 20 | return (void*)result; 21 | } 22 | 23 | 24 | 25 | int main() { 26 | pthread_t tid; 27 | int arg = 80; 28 | int *result = nullptr; 29 | int ret = 0; 30 | 31 | ret = pthread_create(&tid, nullptr, &doubleValue, &arg); 32 | ret = pthread_join(tid, (void**)&result); 33 | 34 | cout << (*result) << endl; 35 | 36 | delete result; 37 | result = nullptr; 38 | 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /cpp/cpp-pthread/demo09a-detach.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | THREAD DETACHING 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | void* foo(void*) { 14 | cout << "foo is starting..." << endl; 15 | 16 | sleep(2); 17 | 18 | cout << "foo is exiting..." << endl; 19 | 20 | pthread_exit(nullptr); 21 | return nullptr; 22 | } 23 | 24 | 25 | 26 | int main() { 27 | pthread_t tidFoo; 28 | int ret = 0; 29 | 30 | 31 | ret = pthread_create(&tidFoo, nullptr, &foo, nullptr); 32 | ret = pthread_detach(tidFoo); 33 | 34 | if (ret) { 35 | cout << "Error: Cannot detach tidFoo" << endl; 36 | } 37 | 38 | 39 | // ret = pthread_join(tidFoo, nullptr); 40 | // if (ret) { 41 | // cout << "Error: Cannot join tidFoo" << endl; 42 | // } 43 | 44 | 45 | // If I comment this statement, 46 | // tidFoo will be forced into terminating with main thread 47 | sleep(3); 48 | 49 | 50 | cout << "Main thread is exiting" << endl; 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /cpp/cpp-pthread/demo09b-detach.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | THREAD DETACHING 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | void* foo(void*) { 14 | int ret = 0; 15 | 16 | cout << "foo is starting..." << endl; 17 | 18 | if ( ret = pthread_detach(pthread_self()) ) { 19 | cout << "Error: Cannot detach" << endl; 20 | } 21 | 22 | sleep(2); 23 | 24 | cout << "foo is exiting..." << endl; 25 | 26 | pthread_exit(nullptr); 27 | return nullptr; 28 | } 29 | 30 | 31 | 32 | int main() { 33 | pthread_t tidFoo; 34 | int ret = 0; 35 | 36 | ret = pthread_create(&tidFoo, nullptr, &foo, nullptr); 37 | 38 | sleep(3); 39 | 40 | cout << "Main thread is exiting" << endl; 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /cpp/cpp-pthread/demo10-yield.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | THREAD YIELDING 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "../cpp-std/mylib-time.hpp" 11 | using namespace std; 12 | 13 | 14 | 15 | using chrmicro = std::chrono::microseconds; 16 | using hrclock = mylib::HiResClock; 17 | 18 | 19 | 20 | void littleSleep(int us) { 21 | auto tpStart = hrclock::now(); 22 | auto tpEnd = tpStart + chrmicro(us); 23 | 24 | int ret = 0; 25 | 26 | do { 27 | // ret = pthread_yield(); 28 | ret = sched_yield(); 29 | } 30 | while (hrclock::now() < tpEnd); 31 | } 32 | 33 | 34 | 35 | int main() { 36 | auto tpStartMeasure = hrclock::now(); 37 | 38 | littleSleep(130); 39 | 40 | auto timeElapsed = hrclock::getTimeSpan(tpStartMeasure); 41 | 42 | cout << "Elapsed time: " << timeElapsed.count() << " microseonds" << endl; 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /cpp/cpp-pthread/demo11b-exec-service.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | EXECUTOR SERVICES AND THREAD POOLS 3 | 4 | Executor services in C++ POSIX threading are not supported by default. 5 | So, I use mylib::ExecService for this demonstration. 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | #include "mylib-execservice.hpp" 12 | using namespace std; 13 | 14 | 15 | 16 | int main() { 17 | constexpr int NUM_THREADS = 2; 18 | constexpr int NUM_TASKS = 5; 19 | 20 | auto execService = mylib::ExecService(NUM_THREADS); 21 | 22 | for (int i = 0; i < NUM_TASKS; ++i) { 23 | execService.submit([=] { 24 | char id = 'A' + i; 25 | cout << "Task " << id << " is starting" << endl; 26 | sleep(3); 27 | cout << "Task " << id << " is completed" << endl; 28 | }); 29 | } 30 | 31 | cout << "All tasks are submitted" << endl; 32 | 33 | execService.waitTaskDone(); 34 | cout << "All tasks are completed" << endl; 35 | 36 | execService.shutdown(); 37 | 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /cpp/cpp-pthread/demo12a-race-condition.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | RACE CONDITIONS 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | void* doTask(void* arg) { 14 | int index = *(int*) arg; 15 | 16 | sleep(1); 17 | 18 | cout << index; 19 | 20 | pthread_exit(nullptr); 21 | return nullptr; 22 | } 23 | 24 | 25 | 26 | int main() { 27 | constexpr int NUM_THREADS = 4; 28 | 29 | pthread_t lstTid[NUM_THREADS]; 30 | int lstArg[NUM_THREADS]; 31 | 32 | int ret = 0; 33 | 34 | 35 | for (int i = 0; i < NUM_THREADS; ++i) { 36 | lstArg[i] = i; 37 | ret = pthread_create(&lstTid[i], nullptr, &doTask, &lstArg[i]); 38 | } 39 | 40 | for (auto&& tid : lstTid) { 41 | ret = pthread_join(tid, nullptr); 42 | } 43 | 44 | 45 | cout << endl; 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /cpp/cpp-pthread/demo12b01-data-race-single.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | DATA RACES 3 | Version 01: Without multithreading 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | int *a = nullptr; 14 | int N = 0; 15 | 16 | 17 | 18 | int getResult() { 19 | a = (int*)calloc(sizeof(int), N + 1); 20 | 21 | for (int i = 1; i <= N; ++i) 22 | if (0 == i % 2 || 0 == i % 3) 23 | a[i] = 1; 24 | 25 | int result = 0; 26 | 27 | for (int i = 1; i <= N; ++i) 28 | if (a[i]) 29 | ++result; 30 | 31 | free(a); 32 | a = nullptr; 33 | 34 | return result; 35 | } 36 | 37 | 38 | 39 | int main() { 40 | N = 8; 41 | 42 | int result = getResult(); 43 | 44 | cout << "Numbers of integers that are divisible by 2 or 3 is: " << result << endl; 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /cpp/cpp-pthread/demo12bex-data-race-fork.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | DATA RACES 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | int main() { 14 | int pid = 0; 15 | 16 | pid = fork(); 17 | 18 | if (-1 == pid) { 19 | cerr << "Cannot fork" << endl; 20 | return 1; 21 | } 22 | 23 | 24 | ofstream ofs; 25 | ofs.open("tmp-output.txt"); 26 | 27 | if (ofs.fail()) { 28 | return 1; 29 | } 30 | 31 | cout << "Writing to the file..." << endl; 32 | 33 | ofs << pid << endl; 34 | 35 | ofs.close(); 36 | return 0; 37 | } 38 | 39 | 40 | /* 41 | The content of the file is UNKNOWN. 42 | It may be: 43 | 0 44 | 45 | or 46 | 34 47 | 48 | or 49 | 0 50 | 34 51 | 52 | or 53 | 34 54 | 0 55 | 56 | Assume that 34 and 0 are process ids. 57 | */ 58 | -------------------------------------------------------------------------------- /cpp/cpp-pthread/demo12c01-race-cond-data-race.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | RACE CONDITIONS AND DATA RACES 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | int counter = 0; 14 | 15 | 16 | 17 | void* increaseCounter(void*) { 18 | sleep(1); 19 | 20 | for (int i = 0; i < 1000; ++i) { 21 | counter += 1; 22 | } 23 | 24 | pthread_exit(nullptr); 25 | return nullptr; 26 | } 27 | 28 | 29 | 30 | int main() { 31 | constexpr int NUM_THREADS = 16; 32 | pthread_t lstTid[NUM_THREADS]; 33 | int ret = 0; 34 | 35 | for (int i = 0; i < NUM_THREADS; ++i) { 36 | ret = pthread_create(&lstTid[i], nullptr, &increaseCounter, nullptr); 37 | } 38 | 39 | for (int i = 0; i < NUM_THREADS; ++i) { 40 | ret = pthread_join(lstTid[i], nullptr); 41 | } 42 | 43 | cout << "counter = " << counter << endl; 44 | // We are NOT sure that counter = 16000 45 | 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /cpp/cpp-pthread/demo12c02-race-cond-data-race.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | RACE CONDITIONS AND DATA RACES 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | int counter = 0; 14 | 15 | 16 | 17 | void* doTaskA(void*) { 18 | sleep(1); 19 | 20 | while (counter < 10) 21 | ++counter; 22 | 23 | cout << "A won !!!" << endl; 24 | 25 | pthread_exit(nullptr); 26 | return nullptr; 27 | } 28 | 29 | 30 | 31 | void* doTaskB(void*) { 32 | sleep(1); 33 | 34 | while (counter > -10) 35 | --counter; 36 | 37 | cout << "B won !!!" << endl; 38 | 39 | pthread_exit(nullptr); 40 | return nullptr; 41 | } 42 | 43 | 44 | 45 | int main() { 46 | pthread_t tidA, tidB; 47 | int ret = 0; 48 | 49 | ret = pthread_create(&tidA, nullptr, &doTaskA, nullptr); 50 | ret = pthread_create(&tidB, nullptr, &doTaskB, nullptr); 51 | 52 | ret = pthread_join(tidA, nullptr); 53 | ret = pthread_join(tidB, nullptr); 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /cpp/cpp-pthread/demo13a-mutex.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | MUTEXES 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; 14 | int counter = 0; 15 | 16 | 17 | 18 | void* doTask(void*) { 19 | sleep(1); 20 | 21 | pthread_mutex_lock(&mut); 22 | 23 | for (int i = 0; i < 1000; ++i) 24 | ++counter; 25 | 26 | pthread_mutex_unlock(&mut); 27 | 28 | pthread_exit(nullptr); 29 | return nullptr; 30 | } 31 | 32 | 33 | 34 | int main() { 35 | constexpr int NUM_THREADS = 16; 36 | pthread_t lstTid[NUM_THREADS]; 37 | int ret = 0; 38 | 39 | for (auto&& tid : lstTid) { 40 | ret = pthread_create(&tid, nullptr, &doTask, nullptr); 41 | } 42 | 43 | for (auto&& tid : lstTid) { 44 | ret = pthread_join(tid, nullptr); 45 | } 46 | 47 | cout << "counter = " << counter << endl; 48 | // We are sure that counter = 16000 49 | 50 | ret = pthread_mutex_destroy(&mut); 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /cpp/cpp-pthread/demo15a-deadlock.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | DEADLOCK 3 | Version A 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; 14 | 15 | 16 | 17 | void* doTask(void* arg) { 18 | auto name = (const char*) arg; 19 | 20 | pthread_mutex_lock(&mut); 21 | 22 | cout << name << " acquired resource" << endl; 23 | 24 | // pthread_mutex_unlock(&mut); // Forget this statement ==> deadlock 25 | 26 | pthread_exit(nullptr); 27 | return nullptr; 28 | } 29 | 30 | 31 | 32 | int main() { 33 | pthread_t tidFoo, tidBar; 34 | int ret = 0; 35 | 36 | ret = pthread_create(&tidFoo, nullptr, &doTask, (void*)"foo"); 37 | ret = pthread_create(&tidBar, nullptr, &doTask, (void*)"bar"); 38 | 39 | ret = pthread_join(tidFoo, nullptr); 40 | ret = pthread_join(tidBar, nullptr); 41 | 42 | cout << "You will never see this statement due to deadlock!" << endl; 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /cpp/cpp-pthread/demo23a-thread-local.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | THREAD-LOCAL STORAGE 3 | Introduction 4 | 5 | The code is specific for gcc. 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | using namespace std; 12 | 13 | 14 | 15 | __thread int value = 123; 16 | 17 | 18 | 19 | void* doTask(void* arg) { 20 | cout << value << endl; 21 | pthread_exit(nullptr); 22 | return nullptr; 23 | } 24 | 25 | 26 | 27 | int main() { 28 | pthread_t tid; 29 | int ret = 0; 30 | 31 | // Main thread sets value = 999 32 | value = 999; 33 | cout << value << endl; 34 | 35 | // Child thread gets value 36 | // Expected output: 123 37 | ret = pthread_create(&tid, nullptr, &doTask, nullptr); 38 | ret = pthread_join(tid, nullptr); 39 | 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /cpp/cpp-pthread/demo24-volatile.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | THE VOLATILE KEYWORD 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | volatile bool isRunning; 14 | 15 | 16 | 17 | void* doTask(void*) { 18 | while (isRunning) { 19 | cout << "Running..." << endl; 20 | sleep(2); 21 | } 22 | 23 | pthread_exit(nullptr); 24 | return nullptr; 25 | } 26 | 27 | 28 | 29 | int main() { 30 | pthread_t tid; 31 | int ret = 0; 32 | 33 | isRunning = true; 34 | ret = pthread_create(&tid, nullptr, &doTask, nullptr); 35 | 36 | sleep(6); 37 | isRunning = false; 38 | 39 | ret = pthread_join(tid, nullptr); 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /cpp/cpp-pthread/demo25a-atomic.c: -------------------------------------------------------------------------------- 1 | /* 2 | ATOMIC ACCESS 3 | 4 | In this demo, I use raw C language (not C++). 5 | */ 6 | 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | 14 | volatile int counter; 15 | 16 | 17 | 18 | void* doTask(void* arg) { 19 | sleep(1); 20 | counter += 1; 21 | 22 | pthread_exit(NULL); 23 | return NULL; 24 | } 25 | 26 | 27 | 28 | int main() { 29 | counter = 0; 30 | 31 | pthread_t lstTid[1000]; 32 | int ret = 0; 33 | 34 | for (int i = 0; i < 1000; ++i) { 35 | ret = pthread_create(&lstTid[i], NULL, &doTask, NULL); 36 | } 37 | 38 | for (int i = 0; i < 1000; ++i) { 39 | ret = pthread_join(lstTid[i], NULL); 40 | } 41 | 42 | // Unpredictable result 43 | printf("counter = %d \n", counter); 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /cpp/cpp-pthread/demo25b-atomic.c: -------------------------------------------------------------------------------- 1 | /* 2 | ATOMIC ACCESS 3 | 4 | In this demo, I use raw C language (not C++). 5 | */ 6 | 7 | 8 | #include 9 | #include 10 | #include // C11 atomic 11 | #include 12 | 13 | 14 | 15 | atomic_int counter; 16 | 17 | 18 | 19 | void* doTask(void* arg) { 20 | sleep(1); 21 | atomic_fetch_add(&counter, 1); 22 | 23 | pthread_exit(NULL); 24 | return NULL; 25 | } 26 | 27 | 28 | 29 | int main() { 30 | atomic_store(&counter, 0); // Assign counter = 0 31 | 32 | pthread_t lstTid[1000]; 33 | int ret = 0; 34 | 35 | for (int i = 0; i < 1000; ++i) { 36 | ret = pthread_create(&lstTid[i], NULL, &doTask, NULL); 37 | } 38 | 39 | for (int i = 0; i < 1000; ++i) { 40 | ret = pthread_join(lstTid[i], NULL); 41 | } 42 | 43 | // counter = 1000 44 | printf("counter = %d \n", counter); 45 | 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /cpp/cpp-pthread/demoex-signal.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | 8 | 9 | void signalHandler(int sig) { 10 | cout << "caught signal " << sig << endl; 11 | // signal(SIGSEGV, signalHandler); 12 | } 13 | 14 | 15 | 16 | void* func(void* arg) { 17 | cout << "foo" << endl; 18 | sleep(5); 19 | 20 | pthread_exit(nullptr); 21 | return nullptr; 22 | } 23 | 24 | 25 | 26 | int main() { 27 | pthread_t tid; 28 | 29 | signal(SIGSEGV, signalHandler); // Register signal handler before going multithread 30 | 31 | pthread_create(&tid, nullptr, &func, nullptr); 32 | sleep(1); // Leave time for initialization 33 | 34 | pthread_kill(tid, SIGSEGV); 35 | 36 | pthread_join(tid, NULL); 37 | 38 | cout << "bar" << endl; 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /cpp/cpp-pthread/exer05-util.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _EXER05_UTIL_HPP_ 2 | #define _EXER05_UTIL_HPP_ 3 | 4 | 5 | 6 | struct WorkerScProdArg { 7 | double const* u = nullptr; 8 | double const* v = nullptr; 9 | int sizeVector = 0; 10 | double* res = nullptr; 11 | }; 12 | 13 | 14 | 15 | void* workerScalarProduct(void* argVoid) { 16 | auto arg = (WorkerScProdArg*) argVoid; 17 | auto u = arg->u; 18 | auto v = arg->v; 19 | auto sizeVector = arg->sizeVector; 20 | auto res = arg->res; 21 | 22 | double sum = 0; 23 | 24 | for (int i = sizeVector - 1; i >= 0; --i) { 25 | sum += u[i] * v[i]; 26 | } 27 | 28 | (*res) = sum; 29 | 30 | return nullptr; 31 | } 32 | 33 | 34 | 35 | #endif // _EXER05_UTIL_HPP_ 36 | -------------------------------------------------------------------------------- /cpp/cpp-pthread/exer08-exec-service-itask.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _MY_EXEC_SERVICE_ITASK_HPP_ 2 | #define _MY_EXEC_SERVICE_ITASK_HPP_ 3 | 4 | 5 | 6 | // interface ITask 7 | class ITask { 8 | public: 9 | virtual ~ITask() = default; 10 | virtual void run() = 0; 11 | }; 12 | 13 | 14 | 15 | #endif // _MY_EXEC_SERVICE_ITASK_HPP_ 16 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo00.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | INTRODUCTION TO MULTITHREADING 3 | You should try running this app several times and see results. 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | void doTask() { 14 | for (int i = 0; i < 300; ++i) 15 | cout << "B"; 16 | } 17 | 18 | 19 | 20 | int main() { 21 | std::thread th(&doTask); 22 | 23 | for (int i = 0; i < 300; ++i) 24 | cout << "A"; 25 | 26 | th.join(); 27 | 28 | cout << endl; 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo01a01-hello.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | HELLO WORLD VERSION MULTITHREADING 3 | Version A01: Using functions 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | void doTask() { 14 | cout << "Hello from example thread" << endl; 15 | } 16 | 17 | 18 | 19 | int main() { 20 | std::thread th(&doTask); 21 | 22 | cout << "Hello from main thread" << endl; 23 | 24 | th.join(); 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo01a02-hello.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | HELLO WORLD VERSION MULTITHREADING 3 | Version A02: Using functions allowing passing 2 arguments 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | void doTask(char const* message, int number) { 14 | cout << message << " " << number << endl; 15 | } 16 | 17 | 18 | 19 | int main() { 20 | std::thread th(&doTask, "Good day", 19); 21 | th.join(); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo01b-hello-class01.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | HELLO WORLD VERSION MULTITHREADING 3 | Version B: Using class methods 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | 13 | 14 | class Example { 15 | public: 16 | void doTask(string message) { 17 | cout << message << endl; 18 | } 19 | }; 20 | 21 | 22 | 23 | int main() { 24 | Example example; 25 | 26 | std::thread th(&Example::doTask, &example, "Good day"); 27 | 28 | th.join(); 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo01b-hello-class02.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | HELLO WORLD VERSION MULTITHREADING 3 | Version B: Using class methods 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | 13 | 14 | class Example { 15 | public: 16 | void run() { 17 | std::thread th(&Example::doTask, this, "Good day"); 18 | th.join(); 19 | } 20 | 21 | private: 22 | void doTask(string message) { 23 | cout << message << endl; 24 | } 25 | }; 26 | 27 | 28 | 29 | int main() { 30 | Example example; 31 | example.run(); 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo01b-hello-class03.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | HELLO WORLD VERSION MULTITHREADING 3 | Version B: Using class methods 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | 13 | 14 | class Example { 15 | public: 16 | void run() { 17 | std::thread th(&Example::doTask, "Good day"); 18 | th.join(); 19 | } 20 | 21 | private: 22 | static void doTask(string message) { 23 | cout << message << endl; 24 | } 25 | }; 26 | 27 | 28 | 29 | int main() { 30 | Example example; 31 | example.run(); 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo01b-hello-functor.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | HELLO WORLD VERSION MULTITHREADING 3 | Version B: Using functors 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | 13 | 14 | class Example { 15 | public: 16 | void operator()(string message) { 17 | cout << message << endl; 18 | } 19 | }; 20 | 21 | 22 | 23 | int main() { 24 | Example example; 25 | 26 | std::thread th(example, "Good day"); 27 | 28 | th.join(); 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo01c-hello-lambda.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | HELLO WORLD VERSION MULTITHREADING 3 | Version C: Using lambdas 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | 13 | 14 | int main() { 15 | auto doTask = [](string message) { 16 | cout << message << endl; 17 | }; 18 | 19 | std::thread th(doTask, "Good day"); 20 | 21 | th.join(); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo02-join.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | THREAD JOINS 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | 11 | 12 | void doHeavyTask() { 13 | // Do a heavy task, which takes a little time 14 | for (int i = 0; i < 2000000000; ++i); 15 | 16 | cout << "Done!" << endl; 17 | } 18 | 19 | 20 | 21 | int main() { 22 | std::thread th(&doHeavyTask); 23 | 24 | th.join(); 25 | 26 | cout << "Good bye!" << endl; 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo03a-pass-arg.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | PASSING ARGUMENTS 3 | Version A: Passing multiple arguments with various data types 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | using namespace std; 12 | 13 | 14 | 15 | struct Point { 16 | int x; 17 | int y; 18 | 19 | Point(int x, int y): x(x), y(y) { } 20 | }; 21 | 22 | 23 | 24 | void doTask(int a, double b, string c, char const* d, Point e) { 25 | char buffer[50] = { 0 }; 26 | std::sprintf(buffer, "%d %.1f %s %s (%d %d)", a, b, c.data(), d, e.x, e.y); 27 | cout << buffer << endl; 28 | } 29 | 30 | 31 | 32 | int main() { 33 | auto thFoo = std::thread(&doTask, 1, 2, "red", "red", Point(0, 0)); 34 | auto thBar = std::thread(&doTask, 3, 4, "blue", "blue", Point(9, 9)); 35 | 36 | thFoo.join(); 37 | thBar.join(); 38 | 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo03b-pass-arg.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | PASSING ARGUMENTS 3 | Version B: Passing constant references 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | 13 | 14 | void doTask(const string& msg) { 15 | cout << msg << endl; 16 | } 17 | 18 | 19 | 20 | int main() { 21 | auto thFoo = std::thread(&doTask, "foo"); 22 | auto thBar = std::thread(&doTask, "bar"); 23 | 24 | thFoo.join(); 25 | thBar.join(); 26 | 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo04a-sleep.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SLEEP 3 | Version A: Sleep for a specific duration 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | using namespace std; 12 | 13 | 14 | 15 | void doTask(string name) { 16 | cout << name << " is sleeping" << endl; 17 | std::this_thread::sleep_for(std::chrono::seconds(3)); 18 | cout << name << " wakes up" << endl; 19 | } 20 | 21 | 22 | 23 | int main() { 24 | auto thFoo = std::thread(&doTask, "foo"); 25 | 26 | thFoo.join(); 27 | 28 | cout << "Good bye" << endl; 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo05-id.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | GETTING THREAD'S ID 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | void doTask() { 14 | std::this_thread::sleep_for(std::chrono::seconds(2)); 15 | cout << std::this_thread::get_id() << endl; 16 | } 17 | 18 | 19 | 20 | int main() { 21 | auto thFoo = std::thread(&doTask); 22 | auto thBar = std::thread(&doTask); 23 | 24 | cout << "foo's id: " << thFoo.get_id() << endl; 25 | cout << "bar's id: " << thBar.get_id() << endl; 26 | 27 | thFoo.join(); 28 | thBar.join(); 29 | 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo06a-list-threads.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | LIST OF MULTIPLE THREADS 3 | Version A: Using standard arrays 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | void doTask(int index) { 14 | cout << index; 15 | } 16 | 17 | 18 | 19 | int main() { 20 | constexpr int NUM_THREADS = 5; 21 | 22 | std::thread lstTh[NUM_THREADS]; 23 | 24 | for (int i = 0; i < NUM_THREADS; ++i) { 25 | lstTh[i] = std::thread(&doTask, i); 26 | } 27 | 28 | for (auto&& th : lstTh) { 29 | th.join(); 30 | } 31 | 32 | cout << endl; 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo06b-list-threads.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | LIST OF MULTIPLE THREADS 3 | Version B: Using the std::vector 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | 13 | 14 | void doTask(int index) { 15 | cout << index; 16 | } 17 | 18 | 19 | 20 | int main() { 21 | constexpr int NUM_THREADS = 5; 22 | 23 | vector lstTh; 24 | 25 | for (int i = 0; i < NUM_THREADS; ++i) { 26 | lstTh.push_back(std::thread(&doTask, i)); 27 | 28 | // or... 29 | // auto th = std::thread(&doTask, i); 30 | // lstTh.push_back(std::move(th)); // Because std::thread does not have copy constructors 31 | } 32 | 33 | for (auto&& th : lstTh) { 34 | th.join(); 35 | } 36 | 37 | cout << endl; 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo07-terminate.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | FORCING A THREAD TO TERMINATE (i.e. killing the thread) 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | volatile bool isRunning; 14 | 15 | 16 | 17 | void doTask() { 18 | while (isRunning) { 19 | cout << "Running..." << endl; 20 | std::this_thread::sleep_for(std::chrono::seconds(2)); 21 | } 22 | } 23 | 24 | 25 | 26 | int main() { 27 | isRunning = true; 28 | auto th = std::thread(&doTask); 29 | 30 | std::this_thread::sleep_for(std::chrono::seconds(6)); 31 | isRunning = false; 32 | 33 | th.join(); 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo08a-return-value.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | GETTING RETURNED VALUES FROM THREADS 3 | Version A: Using pointers or references (traditional way) 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | void doubleValue(int arg, int* res) { 14 | (*res) = arg * 2; 15 | } 16 | 17 | 18 | 19 | void squareValue(int arg, int& res) { 20 | res = arg * arg; 21 | } 22 | 23 | 24 | 25 | int main() { 26 | int result[3]; 27 | 28 | auto thFoo = std::thread(&doubleValue, 5, &result[0]); 29 | auto thBar = std::thread(&doubleValue, 80, &result[1]); 30 | auto thEgg = std::thread(&squareValue, 7, std::ref(result[2])); 31 | 32 | thFoo.join(); 33 | thBar.join(); 34 | thEgg.join(); 35 | 36 | cout << result[0] << endl; 37 | cout << result[1] << endl; 38 | cout << result[2] << endl; 39 | 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo08b-return-value.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | GETTING RETURNED VALUES FROM THREADS 3 | Version B: Using std::future with the promise 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | using namespace std; 12 | 13 | 14 | 15 | void doubleValue(int arg, std::promise & prom) { 16 | int result = arg * 2; 17 | std::this_thread::sleep_for(std::chrono::seconds(2)); 18 | 19 | prom.set_value(result); 20 | 21 | std::this_thread::sleep_for(std::chrono::seconds(2)); 22 | cout << "This thread is exiting" << endl; 23 | } 24 | 25 | 26 | 27 | int main() { 28 | auto prom = std::promise(); 29 | auto fut = prom.get_future(); // fut is std::future 30 | 31 | auto th = std::thread(&doubleValue, 5, std::ref(prom)); 32 | 33 | // Block until prom.set_value() executes 34 | int result = fut.get(); 35 | 36 | cout << result << endl; 37 | 38 | th.join(); 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo08c-return-value.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | GETTING RETURNED VALUES FROM THREADS 3 | Version C: Using std::future with the packaged_task 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | using namespace std; 14 | 15 | 16 | 17 | string doubleValue(int arg) { 18 | int result = arg * 2; 19 | std::this_thread::sleep_for(std::chrono::seconds(2)); 20 | 21 | cout << "This thread is exiting" << endl; 22 | return to_string(result); 23 | } 24 | 25 | 26 | 27 | int main() { 28 | auto ptask = std::packaged_task(doubleValue); 29 | auto fut = ptask.get_future(); // fut is std::future 30 | 31 | auto th = std::thread(std::move(ptask), 5); 32 | 33 | // Block until ptask finishes 34 | string result = fut.get(); 35 | 36 | cout << result << endl; 37 | 38 | th.join(); 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo09-detach.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | THREAD DETACHING 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | void foo() { 14 | cout << "foo is starting..." << endl; 15 | 16 | std::this_thread::sleep_for(std::chrono::seconds(2)); 17 | 18 | cout << "foo is exiting..." << endl; 19 | } 20 | 21 | 22 | 23 | int main() { 24 | auto thFoo = std::thread(&foo); 25 | thFoo.detach(); 26 | 27 | 28 | // If I comment this statement, 29 | // thFoo will be forced into terminating with main thread 30 | std::this_thread::sleep_for(std::chrono::seconds(3)); 31 | 32 | 33 | cout << "Main thread is exiting" << endl; 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo10-yield.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | THREAD YIELDING 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | #include "mylib-time.hpp" 10 | using namespace std; 11 | 12 | 13 | 14 | using chrmicro = std::chrono::microseconds; 15 | using hrclock = mylib::HiResClock; 16 | 17 | 18 | 19 | void littleSleep(int us) { 20 | auto tpStart = hrclock::now(); 21 | auto tpEnd = tpStart + chrmicro(us); 22 | 23 | do { 24 | std::this_thread::yield(); 25 | } 26 | while (hrclock::now() < tpEnd); 27 | } 28 | 29 | 30 | 31 | int main() { 32 | auto tpStartMeasure = hrclock::now(); 33 | 34 | littleSleep(130); 35 | 36 | auto timeElapsed = hrclock::getTimeSpan(tpStartMeasure); 37 | 38 | cout << "Elapsed time: " << timeElapsed.count() << " microseonds" << endl; 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo12a-race-condition.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | RACE CONDITIONS 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | 13 | 14 | void doTask(int index) { 15 | std::this_thread::sleep_for(std::chrono::seconds(1)); 16 | cout << index; 17 | } 18 | 19 | 20 | 21 | int main() { 22 | constexpr int NUM_THREADS = 4; 23 | vector lstTh; 24 | 25 | for (int i = 0; i < NUM_THREADS; ++i) { 26 | lstTh.push_back( 27 | std::thread(&doTask, i) 28 | ); 29 | } 30 | 31 | for (auto&& th : lstTh) { 32 | th.join(); 33 | } 34 | 35 | cout << endl; 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo12b01-data-race-single.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | DATA RACES 3 | Version 01: Without multithreading 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | 13 | 14 | int getResult(int N) { 15 | vector a; 16 | a.resize(N + 1, false); 17 | 18 | for (int i = 1; i <= N; ++i) 19 | if (0 == i % 2 || 0 == i % 3) 20 | a[i] = true; 21 | 22 | // result = sum of a (i.e. counting number of true values in a) 23 | int result = std::accumulate(a.begin(), a.end(), 0); 24 | return result; 25 | } 26 | 27 | 28 | 29 | int main() { 30 | constexpr int N = 8; 31 | 32 | int result = getResult(N); 33 | 34 | cout << "Number of integers that are divisible by 2 or 3 is: " << result << endl; 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo12b02-data-race-multi.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | DATA RACES 3 | Version 02: Multithreading 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | using namespace std; 12 | 13 | 14 | 15 | void markDiv2(vector & a, int N) { 16 | for (int i = 2; i <= N; i += 2) 17 | a[i] = true; 18 | } 19 | 20 | 21 | 22 | void markDiv3(vector & a, int N) { 23 | for (int i = 3; i <= N; i += 3) 24 | a[i] = true; 25 | } 26 | 27 | 28 | 29 | int main() { 30 | constexpr int N = 8; 31 | 32 | vector a; 33 | a.resize(N + 1, false); 34 | 35 | auto thDiv2 = std::thread(&markDiv2, std::ref(a), N); 36 | auto thDiv3 = std::thread(&markDiv3, std::ref(a), N); 37 | thDiv2.join(); 38 | thDiv3.join(); 39 | 40 | // result = sum of a (i.e. counting numbers of true values in a) 41 | int result = std::accumulate(a.begin(), a.end(), 0); 42 | 43 | cout << "Number of integers that are divisible by 2 or 3 is: " << result << endl; 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo12c01-race-cond-data-race.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | RACE CONDITIONS AND DATA RACES 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | int counter = 0; 14 | 15 | 16 | 17 | void increaseCounter() { 18 | std::this_thread::sleep_for(std::chrono::seconds(1)); 19 | 20 | for (int i = 0; i < 1000; ++i) { 21 | counter += 1; 22 | } 23 | } 24 | 25 | 26 | 27 | int main() { 28 | constexpr int NUM_THREADS = 16; 29 | std::thread lstTh[NUM_THREADS]; 30 | 31 | for (auto&& th : lstTh) { 32 | th = std::thread(&increaseCounter); 33 | } 34 | 35 | for (auto&& th : lstTh) { 36 | th.join(); 37 | } 38 | 39 | cout << "counter = " << counter << endl; 40 | // We are NOT sure that counter = 16000 41 | 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo13a-mutex.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | MUTEXES 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | 13 | 14 | std::mutex mut; 15 | int counter = 0; 16 | 17 | 18 | 19 | void doTask() { 20 | std::this_thread::sleep_for(std::chrono::seconds(1)); 21 | 22 | mut.lock(); 23 | 24 | for (int i = 0; i < 1000; ++i) 25 | ++counter; 26 | 27 | mut.unlock(); 28 | } 29 | 30 | 31 | 32 | int main() { 33 | constexpr int NUM_THREADS = 16; 34 | std::thread lstTh[NUM_THREADS]; 35 | 36 | for (auto&& th : lstTh) { 37 | th = std::thread(&doTask); 38 | } 39 | 40 | for (auto&& th : lstTh) { 41 | th.join(); 42 | } 43 | 44 | cout << "counter = " << counter << endl; 45 | // We are sure that counter = 16000 46 | 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo13c-mutex-trylock.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | MUTEXES 3 | Locking with a nonblocking mutex 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | using namespace std; 12 | 13 | 14 | 15 | std::mutex mut; 16 | int counter = 0; 17 | 18 | 19 | 20 | void doTask() { 21 | std::this_thread::sleep_for(std::chrono::seconds(1)); 22 | 23 | if (false == mut.try_lock()) { 24 | return; 25 | } 26 | 27 | for (int i = 0; i < 10000; ++i) 28 | ++counter; 29 | 30 | mut.unlock(); 31 | } 32 | 33 | 34 | 35 | int main() { 36 | constexpr int NUM_THREADS = 3; 37 | std::thread lstTh[NUM_THREADS]; 38 | 39 | for (auto&& th : lstTh) { 40 | th = std::thread(&doTask); 41 | } 42 | 43 | for (auto&& th : lstTh) { 44 | th.join(); 45 | } 46 | 47 | cout << "counter = " << counter << endl; 48 | // counter can be 10000, 20000 or 30000 49 | 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo15a-deadlock.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | DEADLOCK 3 | Version A 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | using namespace std; 12 | 13 | 14 | 15 | std::mutex mut; 16 | 17 | 18 | 19 | void doTask(std::string name) { 20 | mut.lock(); 21 | 22 | cout << name << " acquired resource" << endl; 23 | 24 | // mut.unlock(); // Forget this statement ==> deadlock 25 | } 26 | 27 | 28 | 29 | int main() { 30 | auto thFoo = std::thread(&doTask, "foo"); 31 | auto thBar = std::thread(&doTask, "bar"); 32 | 33 | thFoo.join(); 34 | thBar.join(); 35 | 36 | cout << "You will never see this statement due to deadlock!" << endl; 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo17a-reentrant-lock.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | REENTRANT LOCKS (RECURSIVE MUTEXES) 3 | Version A: Introduction to reentrant locks 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | 13 | 14 | std::mutex mut; 15 | 16 | 17 | 18 | void doTask() { 19 | mut.lock(); 20 | cout << "First time acquiring the resource" << endl; 21 | 22 | mut.lock(); 23 | cout << "Second time acquiring the resource" << endl; 24 | 25 | mut.unlock(); 26 | mut.unlock(); 27 | } 28 | 29 | 30 | 31 | int main() { 32 | auto th = std::thread(&doTask); 33 | /* 34 | The thread th shall meet deadlock. 35 | So, you will never get output "Second time the acquiring resource". 36 | */ 37 | th.join(); 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo17b-reentrant-lock.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | REENTRANT LOCKS (RECURSIVE MUTEXES) 3 | Version B: Solving the problem from version A 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | 13 | 14 | std::recursive_mutex mut; 15 | 16 | 17 | 18 | void doTask() { 19 | mut.lock(); 20 | cout << "First time acquiring the resource" << endl; 21 | 22 | mut.lock(); 23 | cout << "Second time acquiring the resource" << endl; 24 | 25 | mut.unlock(); 26 | mut.unlock(); 27 | } 28 | 29 | 30 | 31 | void doTaskUsingSyncBlock() { 32 | using uniquelk = std::unique_lock; 33 | 34 | uniquelk lk(mut); 35 | cout << "First time acquiring the resource" << endl; 36 | 37 | { 38 | uniquelk lk(mut); 39 | cout << "Second time acquiring the resource" << endl; 40 | } 41 | } 42 | 43 | 44 | 45 | int main() { 46 | auto th = std::thread(&doTask); 47 | th.join(); 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo21a01-condition-variable.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | CONDITION VARIABLES 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | using namespace std; 12 | 13 | 14 | 15 | std::mutex mut; 16 | std::condition_variable conditionVar; 17 | 18 | 19 | 20 | void foo() { 21 | cout << "foo is waiting..." << endl; 22 | 23 | std::unique_lock mutLock(mut); 24 | conditionVar.wait(mutLock); 25 | 26 | cout << "foo resumed" << endl; 27 | } 28 | 29 | 30 | 31 | void bar() { 32 | std::this_thread::sleep_for(std::chrono::seconds(3)); 33 | conditionVar.notify_one(); 34 | } 35 | 36 | 37 | 38 | int main() { 39 | auto thFoo = std::thread(&foo); 40 | auto thBar = std::thread(&bar); 41 | 42 | thFoo.join(); 43 | thBar.join(); 44 | 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo23a01-thread-local.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | THREAD-LOCAL STORAGE 3 | Introduction 4 | The basic way to use thread-local storage 5 | */ 6 | 7 | 8 | #include 9 | #include 10 | #include 11 | using namespace std; 12 | 13 | 14 | 15 | thread_local string value = "NOT SET"; 16 | 17 | 18 | 19 | void doTask() { 20 | cout << value << endl; 21 | } 22 | 23 | 24 | 25 | int main() { 26 | // Main thread sets value = "APPLE" 27 | value = "APPLE"; 28 | cout << value << endl; 29 | 30 | // Child thread gets value 31 | // Expected output: "NOT SET" 32 | auto th = std::thread(&doTask); 33 | th.join(); 34 | 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo23a02-thread-local.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | THREAD-LOCAL STORAGE 3 | Introduction 4 | The smart-pointer way to use thread-local storage 5 | */ 6 | 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | using namespace std; 13 | 14 | 15 | 16 | thread_local std::shared_ptr value; 17 | 18 | 19 | 20 | string getValue() { 21 | if (nullptr == value.get()) { 22 | value.reset(new string("NOT SET")); 23 | } 24 | 25 | return *value.get(); 26 | } 27 | 28 | 29 | 30 | void doTask() { 31 | cout << getValue() << endl; 32 | } 33 | 34 | 35 | 36 | int main() { 37 | // Main thread sets value = "APPLE" 38 | value.reset(new string("APPLE")); 39 | cout << getValue() << endl; 40 | 41 | // Child thread gets value 42 | // Expected output: "NOT SET" 43 | auto th = std::thread(&doTask); 44 | th.join(); 45 | 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo24-volatile.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | THE VOLATILE KEYWORD 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | volatile bool isRunning; 14 | 15 | 16 | 17 | void doTask() { 18 | while (isRunning) { 19 | cout << "Running..." << endl; 20 | std::this_thread::sleep_for(std::chrono::seconds(2)); 21 | } 22 | } 23 | 24 | 25 | 26 | int main() { 27 | isRunning = true; 28 | auto th = std::thread(&doTask); 29 | 30 | std::this_thread::sleep_for(std::chrono::seconds(6)); 31 | isRunning = false; 32 | 33 | th.join(); 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo25a-atomic.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ATOMIC ACCESS 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | 13 | 14 | volatile int counter = 0; 15 | 16 | 17 | 18 | void doTask() { 19 | std::this_thread::sleep_for(std::chrono::seconds(1)); 20 | counter += 1; 21 | } 22 | 23 | 24 | 25 | int main() { 26 | counter = 0; 27 | 28 | vector lstTh; 29 | 30 | for (int i = 0; i < 1000; ++i) { 31 | lstTh.push_back(std::thread(&doTask)); 32 | } 33 | 34 | for (auto&& th : lstTh) { 35 | th.join(); 36 | } 37 | 38 | // Unpredictable result 39 | cout << "counter = " << counter << endl; 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /cpp/cpp-std/demo25b-atomic.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ATOMIC ACCESS 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | using namespace std; 12 | 13 | 14 | 15 | // std::atomic counter; 16 | std::atomic_int32_t counter; 17 | 18 | 19 | 20 | void doTask() { 21 | std::this_thread::sleep_for(std::chrono::seconds(1)); 22 | counter += 1; 23 | } 24 | 25 | 26 | 27 | int main() { 28 | counter = 0; 29 | 30 | vector lstTh; 31 | 32 | for (int i = 0; i < 1000; ++i) { 33 | lstTh.push_back(std::thread(&doTask)); 34 | } 35 | 36 | for (auto&& th : lstTh) { 37 | th.join(); 38 | } 39 | 40 | // counter = 1000 41 | cout << "counter = " << counter << endl; 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /cpp/cpp-std/exer05-util.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _EXER05_UTIL_HPP_ 2 | #define _EXER05_UTIL_HPP_ 3 | 4 | 5 | 6 | void getScalarProduct(double const* u, double const* v, int sizeVector, double* res) { 7 | double sum = 0; 8 | 9 | for (int i = sizeVector - 1; i >= 0; --i) { 10 | sum += u[i] * v[i]; 11 | } 12 | 13 | (*res) = sum; 14 | } 15 | 16 | 17 | 18 | #endif // _EXER05_UTIL_HPP_ 19 | -------------------------------------------------------------------------------- /cpp/cpp-std/exer08-exec-service-itask.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _MY_EXEC_SERVICE_ITASK_HPP_ 2 | #define _MY_EXEC_SERVICE_ITASK_HPP_ 3 | 4 | 5 | 6 | // interface ITask 7 | class ITask { 8 | public: 9 | virtual ~ITask() = default; 10 | virtual void run() = 0; 11 | }; 12 | 13 | 14 | 15 | #endif // _MY_EXEC_SERVICE_ITASK_HPP_ 16 | -------------------------------------------------------------------------------- /csharp/.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | obj/ 3 | .vs/ 4 | -------------------------------------------------------------------------------- /csharp/IRunnable.cs: -------------------------------------------------------------------------------- 1 | interface IRunnable 2 | { 3 | public abstract void run(); 4 | } 5 | -------------------------------------------------------------------------------- /csharp/Program.cs: -------------------------------------------------------------------------------- 1 | class Program 2 | { 3 | static void Main(string[] args) 4 | { 5 | new Demo00().run(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /csharp/demo/demo00-intro.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * INTRODUCTION TO MULTITHREADING 3 | * You should try running this app several times and see results. 4 | */ 5 | using System; 6 | using System.Threading; 7 | 8 | 9 | 10 | class Demo00 : IRunnable 11 | { 12 | public void run() 13 | { 14 | Thread th = new Thread(doTask); 15 | 16 | th.Start(); 17 | 18 | for (int i = 0; i < 300; ++i) 19 | Console.Write("A"); 20 | } 21 | 22 | private void doTask() 23 | { 24 | for (int i = 0; i < 300; ++i) 25 | Console.Write("B"); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /csharp/demo/demo01a-hello.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * HELLO WORLD VERSION MULTITHREADING 3 | * Version A: Using functions 4 | */ 5 | using System; 6 | using System.Threading; 7 | 8 | 9 | 10 | class Demo01A : IRunnable 11 | { 12 | public void run() 13 | { 14 | Thread th = new Thread(doTask); 15 | // or 16 | // Thread th = new Thread(new ThreadStart(doTask)); 17 | 18 | th.Start(); 19 | Console.WriteLine("Hello from main thread"); 20 | } 21 | 22 | private void doTask() 23 | { 24 | Console.WriteLine("Hello from example thread"); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /csharp/demo/demo01b01-hello.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * HELLO WORLD VERSION MULTITHREADING 3 | * Version B01: Using lambdas with ThreadStart 4 | */ 5 | using System; 6 | using System.Threading; 7 | 8 | 9 | 10 | class Demo01B01 : IRunnable 11 | { 12 | public void run() 13 | { 14 | ThreadStart doTask = new ThreadStart(() => 15 | { 16 | Console.WriteLine("Hello from example thread"); 17 | }); 18 | 19 | Thread th1 = new Thread(doTask); 20 | Thread th2 = new Thread(doTask); 21 | 22 | th1.Start(); 23 | th2.Start(); 24 | 25 | Console.WriteLine("Hello from main thread"); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /csharp/demo/demo01b02-hello.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * HELLO WORLD VERSION MULTITHREADING 3 | * Version B02: Using lambdas 4 | */ 5 | using System; 6 | using System.Threading; 7 | 8 | 9 | 10 | class Demo01B02 : IRunnable 11 | { 12 | public void run() 13 | { 14 | Thread th = new Thread(() => Console.WriteLine("Hello from example thread")); 15 | 16 | th.Start(); 17 | 18 | Console.WriteLine("Hello from main thread"); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /csharp/demo/demo01ex-name.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * HELLO WORLD VERSION MULTITHREADING 3 | * Version extra: Getting thread's name 4 | */ 5 | using System; 6 | using System.Threading; 7 | 8 | 9 | 10 | class Demo01ExtraName : IRunnable 11 | { 12 | public void run() 13 | { 14 | Thread thFoo = new Thread(doTask) 15 | { 16 | Name = "foo" 17 | }; 18 | 19 | Thread thBar = new Thread(doTask); 20 | thBar.Name = "bar"; 21 | 22 | thFoo.Start(); 23 | thBar.Start(); 24 | } 25 | 26 | private void doTask() 27 | { 28 | Console.WriteLine($"My name is {Thread.CurrentThread.Name}"); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /csharp/demo/demo02a-join.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * THREAD JOINS 3 | */ 4 | using System; 5 | using System.Threading; 6 | 7 | 8 | 9 | class Demo02A : IRunnable 10 | { 11 | public void run() 12 | { 13 | Thread th = new Thread(doHeavyTask); 14 | 15 | th.Start(); 16 | th.Join(); 17 | 18 | Console.WriteLine("Good bye!"); 19 | } 20 | 21 | private void doHeavyTask() { 22 | // Do a heavy task, which takes a little time 23 | for (int i = 0; i < 2000000000; ++i); 24 | 25 | Console.WriteLine("Done!"); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /csharp/demo/demo02b-join.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * THREAD JOINS 3 | */ 4 | using System; 5 | using System.Threading; 6 | 7 | 8 | 9 | class Demo02B : IRunnable 10 | { 11 | public void run() 12 | { 13 | Thread thFoo = new Thread(() => Console.WriteLine("foo")); 14 | Thread thBar = new Thread(() => Console.WriteLine("bar")); 15 | 16 | thFoo.Start(); 17 | thBar.Start(); 18 | 19 | // thFoo.Join(); 20 | // thBar.Join(); 21 | 22 | /* 23 | * We do not need to call thFoo.Join() and thBar.Join(). 24 | * The reason is main thread will wait for the completion of all threads before app exits. 25 | */ 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /csharp/demo/demo03a-pass-arg.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * PASSING ARGUMENTS 3 | * Version A: Using lambdas 4 | */ 5 | using System; 6 | using System.Threading; 7 | 8 | 9 | 10 | class Demo03C : IRunnable 11 | { 12 | public void run() 13 | { 14 | Thread thFoo = new Thread(() => doTask(1, 2, "red")); 15 | Thread thBar = new Thread(() => doTask(3, 4, "blue")); 16 | 17 | thFoo.Start(); 18 | thBar.Start(); 19 | } 20 | 21 | 22 | private void doTask(int a, double b, string c) 23 | { 24 | Console.WriteLine($"{a} {b} {c}"); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /csharp/demo/demo03b-pass-arg.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * PASSING ARGUMENTS 3 | * Version B: Traditional way with a single argument of type object 4 | */ 5 | using System; 6 | using System.Threading; 7 | 8 | 9 | 10 | class Demo03A : IRunnable 11 | { 12 | public void run() 13 | { 14 | Thread thFoo = new Thread(doTask); 15 | Thread thBar = new Thread(doTask); 16 | 17 | // or 18 | // Thread thFoo = new Thread(new ParameterizedThreadStart(doTask)); 19 | // Thread thBar = new Thread(new ParameterizedThreadStart(doTask)); 20 | 21 | thFoo.Start(new object[] { 1, 2.0, "red" }); 22 | thBar.Start(new object[] { 3, 4.0, "blue" }); 23 | } 24 | 25 | private void doTask(object arg) 26 | { 27 | object[] array = (object[]) arg; 28 | 29 | int a = (int) array[0]; 30 | double b = (double) array[1]; 31 | string c = (string) array[2]; 32 | 33 | Console.WriteLine($"{a} {b} {c}\n"); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /csharp/demo/demo03c-pass-arg.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * PASSING ARGUMENTS 3 | * Version C: Traditional way + dynamic data type 4 | */ 5 | using System; 6 | using System.Threading; 7 | 8 | 9 | 10 | class Demo03B : IRunnable 11 | { 12 | public void run() 13 | { 14 | Thread thFoo = new Thread(doTask); 15 | Thread thBar = new Thread(doTask); 16 | 17 | thFoo.Start(new object[] { 1, 2, "red" }); 18 | thBar.Start(new object[] { 3, 4, "blue" }); 19 | } 20 | 21 | private void doTask(dynamic arg) 22 | { 23 | int a = arg[0]; 24 | double b = arg[1]; 25 | string c = arg[2]; 26 | Console.WriteLine($"{a} {b} {c}\n"); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /csharp/demo/demo03d-pass-arg.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * PASSING ARGUMENTS 3 | * Version D: Passing arguments by capturing them 4 | */ 5 | using System; 6 | using System.Threading; 7 | 8 | 9 | 10 | class Demo03D : IRunnable 11 | { 12 | public void run() 13 | { 14 | const int COUNT = 10; 15 | 16 | new Thread(() => 17 | { 18 | 19 | for (int i = 1; i <= COUNT; ++i) 20 | Console.WriteLine("Foo " + i); 21 | 22 | }).Start(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /csharp/demo/demo04-sleep.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * SLEEP 3 | */ 4 | using System; 5 | using System.Threading; 6 | 7 | 8 | 9 | class Demo04 : IRunnable 10 | { 11 | public void run() 12 | { 13 | var thFoo = new Thread(() => 14 | { 15 | Console.WriteLine("foo is sleeping"); 16 | Thread.Sleep(3000); 17 | Console.WriteLine("foo wakes up"); 18 | }); 19 | 20 | thFoo.Start(); 21 | thFoo.Join(); 22 | 23 | Console.WriteLine("Good bye"); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /csharp/demo/demo05-id.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * GETTING THREAD'S ID 3 | */ 4 | using System; 5 | using System.Threading; 6 | 7 | 8 | 9 | class Demo05 : IRunnable 10 | { 11 | public void run() 12 | { 13 | ThreadStart doTask = () => 14 | { 15 | int id = Thread.CurrentThread.ManagedThreadId; 16 | Console.WriteLine(id); 17 | }; 18 | 19 | Thread thFoo = new Thread(doTask); 20 | Thread thBar = new Thread(doTask); 21 | 22 | Console.WriteLine("foo's id: " + thFoo.ManagedThreadId); 23 | Console.WriteLine("bar's id: " + thBar.ManagedThreadId); 24 | 25 | thFoo.Start(); 26 | thBar.Start(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /csharp/demo/demo06a-list-threads.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * LIST OF MULTIPLE THREADS 3 | * Version A: Using List 4 | */ 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Threading; 8 | 9 | 10 | 11 | class Demo06A : IRunnable 12 | { 13 | public void run() 14 | { 15 | const int NUM_THREADS = 5; 16 | var lstTh = new List(); 17 | 18 | 19 | for (int i = 0; i < NUM_THREADS; ++i) 20 | { 21 | /* 22 | * Due to the reference mechanism, 23 | * if you remove the line "int ith = i", the result will be wrong. 24 | */ 25 | int ith = i; 26 | 27 | lstTh.Add(new Thread(() => 28 | { 29 | Thread.Sleep(500); 30 | Console.WriteLine(ith); 31 | })); 32 | } 33 | 34 | 35 | lstTh.ForEach(th => th.Start()); 36 | // foreach (var th in lstTh) 37 | // { 38 | // th.Start(); 39 | // } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /csharp/demo/demo06b-list-threads.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * LIST OF MULTIPLE THREADS 3 | * Version B: Using Linq 4 | */ 5 | using System; 6 | using System.Linq; 7 | using System.Threading; 8 | 9 | 10 | 11 | class Demo06B : IRunnable 12 | { 13 | public void run() 14 | { 15 | var lstTh = Enumerable.Range(0, 5).Select(index => new Thread(() => 16 | { 17 | Thread.Sleep(500); 18 | Console.WriteLine(index); 19 | })).ToList(); 20 | 21 | lstTh.ForEach(th => th.Start()); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /csharp/demo/demo07-terminate.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * FORCING A THREAD TO TERMINATE (i.e. killing the thread) 3 | * Using a flag to notify the thread 4 | * 5 | * Note: The "volatile" keyword is explained in another demo. 6 | */ 7 | using System; 8 | using System.Threading; 9 | 10 | 11 | 12 | class Demo07 : IRunnable 13 | { 14 | private volatile bool flagStop; 15 | 16 | public void run() 17 | { 18 | flagStop = false; 19 | 20 | var th = new Thread(() => 21 | { 22 | 23 | while (true) 24 | { 25 | if (flagStop) 26 | break; 27 | 28 | Console.WriteLine("Running..."); 29 | 30 | Thread.Sleep(1000); 31 | } 32 | 33 | }); 34 | 35 | th.Start(); 36 | 37 | Thread.Sleep(3000); 38 | flagStop = true; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /csharp/demo/demo08a-return-value.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * GETTING RETURNED VALUES FROM THREADS 3 | */ 4 | using System; 5 | using System.Threading; 6 | 7 | 8 | 9 | class Demo08A : IRunnable 10 | { 11 | public void run() 12 | { 13 | int resFoo = 0, resBar = 0; 14 | 15 | var thFoo = new Thread(() => resFoo = doubleValue(5)); 16 | var thBar = new Thread(() => resBar = doubleValue(80)); 17 | 18 | thFoo.Start(); 19 | thBar.Start(); 20 | 21 | // Wait until thFoo and thBar finish 22 | thFoo.Join(); 23 | thBar.Join(); 24 | 25 | Console.WriteLine(resFoo); 26 | Console.WriteLine(resBar); 27 | } 28 | 29 | 30 | private int doubleValue(int value) 31 | { 32 | return value * 2; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /csharp/demo/demo08b-return-value.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * GETTING RETURNED VALUES FROM THREADS 3 | * Using AutoResetEvent to notify the thread which is waiting for returned values 4 | */ 5 | using System; 6 | using System.Threading; 7 | 8 | 9 | 10 | class Demo08B : IRunnable 11 | { 12 | private AutoResetEvent re; 13 | private int result; 14 | 15 | 16 | public void run() 17 | { 18 | re = new AutoResetEvent(false); 19 | 20 | new Thread(() => doubleValue(5)).Start(); 21 | 22 | // Wait until we receive a notification from re 23 | re.WaitOne(); 24 | 25 | Console.WriteLine(result); 26 | } 27 | 28 | 29 | private void doubleValue(int value) 30 | { 31 | result = value * 2; 32 | 33 | Thread.Sleep(2000); 34 | re.Set(); // Notify the threads that are waiting for re 35 | 36 | Thread.Sleep(2000); 37 | Console.WriteLine("This thread is exiting"); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /csharp/demo/demo09-detach.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * THREAD DETACHING 3 | */ 4 | using System; 5 | using System.Threading; 6 | 7 | 8 | 9 | class Demo09 : IRunnable 10 | { 11 | public void run() 12 | { 13 | var thFoo = new Thread(() => { 14 | Console.WriteLine("foo is starting..."); 15 | Thread.Sleep(2000); 16 | Console.WriteLine("foo is exiting..."); 17 | }); 18 | 19 | 20 | thFoo.IsBackground = true; 21 | thFoo.Start(); 22 | 23 | 24 | // If I comment this statement, 25 | // thFoo will be forced into terminating with main thread 26 | Thread.Sleep(3000); 27 | 28 | 29 | Console.WriteLine("Main thread is exiting"); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /csharp/demo/demo10-yield.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * THREAD YIELDING 3 | */ 4 | using System; 5 | using System.Threading; 6 | 7 | 8 | 9 | class Demo10 : IRunnable 10 | { 11 | public void run() 12 | { 13 | DateTime tpStartMeasure = DateTime.Now; 14 | 15 | littleSleep(1); 16 | 17 | var timeElapsed = DateTime.Now.Subtract(tpStartMeasure).TotalMilliseconds; 18 | 19 | Console.WriteLine($"Elapsed time: {timeElapsed} miliseonds"); 20 | } 21 | 22 | 23 | private void littleSleep(double miliseconds) 24 | { 25 | DateTime tpEnd = DateTime.Now.AddMilliseconds(miliseconds); 26 | 27 | do 28 | { 29 | Thread.Yield(); 30 | } 31 | while (DateTime.Now.CompareTo(tpEnd) < 0); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /csharp/demo/demo11a01-exec-service.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * EXECUTOR SERVICES AND THREAD POOLS 3 | * Version A01: System.Threading.ThreadPool 4 | * Introduction 5 | */ 6 | using System; 7 | using System.Threading; 8 | 9 | 10 | 11 | class Demo11A01 : IRunnable 12 | { 13 | public void run() 14 | { 15 | WaitCallback wcb = (arg) => 16 | { 17 | Console.WriteLine("Hello Multithreading"); 18 | }; 19 | 20 | 21 | ThreadPool.QueueUserWorkItem(wcb); 22 | ThreadPool.QueueUserWorkItem(doTask); 23 | ThreadPool.QueueUserWorkItem(arg => Console.WriteLine("Hello World")); 24 | 25 | 26 | // Wait one second for task completion 27 | Thread.Sleep(1000); 28 | } 29 | 30 | 31 | private void doTask(object arg) 32 | { 33 | Console.WriteLine("Hello the Executor Service"); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /csharp/demo/demo11a02-exec-service.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * EXECUTOR SERVICES AND THREAD POOLS 3 | * Version A02: System.Threading.ThreadPool 4 | * Passing arguments 5 | */ 6 | using System; 7 | using System.Threading; 8 | 9 | 10 | 11 | class Demo11A02 : IRunnable 12 | { 13 | public void run() 14 | { 15 | WaitCallback wcb = (arg) => 16 | { 17 | Console.WriteLine($"Hello Multithreading {arg}"); 18 | }; 19 | 20 | 21 | ThreadPool.QueueUserWorkItem(wcb, 1); 22 | ThreadPool.QueueUserWorkItem(doTask, 2); 23 | 24 | ThreadPool.QueueUserWorkItem( 25 | arg => Console.WriteLine($"Hello World {arg}"), 26 | 3 27 | ); 28 | 29 | 30 | // Wait one second for task completion 31 | Thread.Sleep(1000); 32 | } 33 | 34 | 35 | private void doTask(object arg) 36 | { 37 | Console.WriteLine($"Hello the Executor Service {arg}"); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /csharp/demo/demo11a03-exec-service.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * EXECUTOR SERVICES AND THREAD POOLS 3 | * Version A03: System.Threading.ThreadPool 4 | * Returning values 5 | */ 6 | using System; 7 | using System.Threading; 8 | 9 | 10 | 11 | class Demo11A03 : IRunnable 12 | { 13 | private AutoResetEvent re; 14 | 15 | 16 | public void run() 17 | { 18 | re = new AutoResetEvent(false); 19 | 20 | int[] arg = new int[2]; 21 | arg[0] = 7; // input 22 | 23 | ThreadPool.QueueUserWorkItem(getSquared, arg); 24 | 25 | // Wait until the thread completes 26 | re.WaitOne(); 27 | 28 | int result = arg[1]; 29 | Console.WriteLine(result); 30 | } 31 | 32 | 33 | private void getSquared(dynamic arg) 34 | { 35 | int i = arg[0]; 36 | arg[1] = i * i; 37 | re.Set(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /csharp/demo/demo11a05-exec-service.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * EXECUTOR SERVICES AND THREAD POOLS 3 | * Version A05: System.Threading.ThreadPool 4 | * Waiting for task completion by CountdownEvent 5 | */ 6 | using System; 7 | using System.Threading; 8 | 9 | 10 | 11 | class Demo11A05 : IRunnable 12 | { 13 | public void run() 14 | { 15 | // INIT 16 | const int N = 5; 17 | 18 | var lstResult = new int[N]; 19 | var cde = new CountdownEvent(N); 20 | 21 | 22 | // RUN 23 | for (int i = 0; i < N; ++i) 24 | { 25 | int ith = i; 26 | 27 | ThreadPool.QueueUserWorkItem(_ => 28 | { 29 | lstResult[ith] = ith * ith; 30 | cde.Signal(); 31 | } 32 | ); 33 | } 34 | 35 | 36 | cde.Wait(); 37 | 38 | 39 | // PRINT RESULTS 40 | Array.ForEach(lstResult, res => Console.WriteLine(res)); 41 | 42 | 43 | cde.Dispose(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /csharp/demo/demo11b01-exec-service-parallel.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * EXECUTOR SERVICES AND THREAD POOLS 3 | * Version B01: System.Threading.Tasks.Parallel 4 | * Introduction 5 | */ 6 | using System; 7 | using System.Threading.Tasks; 8 | 9 | 10 | 11 | class Demo11B01 : IRunnable 12 | { 13 | public void run() 14 | { 15 | Action action = arg => 16 | { 17 | Console.WriteLine($"Hello Multithreading {arg}"); 18 | }; 19 | 20 | 21 | Parallel.For(0, 4, action); 22 | // Main thread shall pause until all threads are completed 23 | 24 | Parallel.For(4, 8, doTask); 25 | // Main thread shall pause until all threads are completed 26 | 27 | Parallel.For(8, 12, i => Console.WriteLine($"Hello World {i}")); 28 | // Main thread shall pause until all threads are completed 29 | } 30 | 31 | 32 | private void doTask(int arg) 33 | { 34 | Console.WriteLine($"Hello the Executor Service {arg}"); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /csharp/demo/demo11b02-exec-service-parallel.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * EXECUTOR SERVICES AND THREAD POOLS 3 | * Version B02: System.Threading.Tasks.Parallel 4 | */ 5 | using System; 6 | using System.Threading.Tasks; 7 | 8 | 9 | 10 | class Demo11B02 : IRunnable 11 | { 12 | public void run() 13 | { 14 | // EXAMPLE 1 15 | const int N = 5; 16 | var lstResult = new int[N]; 17 | 18 | Parallel.For(0, N, i => 19 | { 20 | lstResult[i] = i * i; 21 | }); 22 | 23 | Array.ForEach(lstResult, res => Console.Write(res + "\t")); 24 | Console.WriteLine(); 25 | 26 | 27 | // EXAMPLE 2 28 | var lstArg = new double[] { -3.14, -9.8, 0, 1, -6 }; 29 | 30 | Parallel.ForEach(lstArg, arg => 31 | { 32 | Console.Write(Math.Abs(arg) + "\t"); 33 | }); 34 | 35 | Console.WriteLine(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /csharp/demo/demo11c-exec-service.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * EXECUTOR SERVICES AND THREAD POOLS 3 | * Version C: Fixed thread pools 4 | */ 5 | using System; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | 10 | 11 | class Demo11C : IRunnable 12 | { 13 | public void run() 14 | { 15 | const int N = 5; 16 | 17 | var prlOptions = new ParallelOptions { MaxDegreeOfParallelism = 2 }; 18 | 19 | Parallel.For(0, N, prlOptions, 20 | i => 21 | { 22 | char name = (char)(i + 'A'); 23 | Console.WriteLine($"Task {name} is starting"); 24 | Thread.Sleep(3000); 25 | Console.WriteLine($"Task {name} is completed"); 26 | } 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /csharp/demo/demo12a-race-condition.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * RACE CONDITIONS 3 | */ 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Threading; 7 | 8 | 9 | 10 | class Demo12A : IRunnable 11 | { 12 | public void run() 13 | { 14 | const int NUM_THREADS = 5; 15 | var lstTh = new List(); 16 | 17 | 18 | for (int i = 0; i < NUM_THREADS; ++i) 19 | { 20 | int ith = i; 21 | 22 | lstTh.Add(new Thread(() => 23 | { 24 | Thread.Sleep(1000); 25 | Console.WriteLine(ith); 26 | })); 27 | } 28 | 29 | 30 | lstTh.ForEach(th => th.Start()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /csharp/demo/demo12b01-data-race-single.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * DATA RACES 3 | * Version 01: Without multithreading 4 | */ 5 | using System; 6 | using System.Linq; 7 | 8 | 9 | 10 | class Demo12B01 : IRunnable 11 | { 12 | public void run() 13 | { 14 | const int N = 8; 15 | int result = getResult(N); 16 | Console.WriteLine("Numbers of integers that are divisible by 2 or 3 is: " + result); 17 | } 18 | 19 | 20 | private int getResult(int N) 21 | { 22 | var a = Enumerable.Repeat(false, N + 1).ToArray(); 23 | 24 | for (int i = 1; i <= N; ++i) 25 | if (i % 2 == 0 || i % 3 == 0) 26 | a[i] = true; 27 | 28 | // res = number of true values in array 29 | int res = a.Count(val => val); 30 | return res; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /csharp/demo/demo12b02-data-race-multi.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * DATA RACES 3 | * Version 02: Multithreading 4 | */ 5 | using System; 6 | using System.Threading; 7 | using System.Linq; 8 | 9 | 10 | 11 | class Demo12B02 : IRunnable 12 | { 13 | public void run() 14 | { 15 | const int N = 8; 16 | var a = Enumerable.Repeat(false, N + 1).ToArray(); 17 | 18 | 19 | var thDiv2 = new Thread(() => 20 | { 21 | for (int i = 2; i <= N; i += 2) 22 | a[i] = true; 23 | }); 24 | 25 | var thDiv3 = new Thread(() => 26 | { 27 | for (int i = 3; i <= N; i += 3) 28 | a[i] = true; 29 | }); 30 | 31 | 32 | thDiv2.Start(); 33 | thDiv3.Start(); 34 | thDiv2.Join(); 35 | thDiv3.Join(); 36 | 37 | 38 | int result = a.Count(val => val); 39 | Console.WriteLine("Numbers of integers that are divisible by 2 or 3 is: " + result); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /csharp/demo/demo12c01-race-cond-data-race.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * RACE CONDITIONS AND DATA RACES 3 | */ 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Threading; 7 | 8 | 9 | 10 | class Demo12C01 : IRunnable 11 | { 12 | private int counter; 13 | 14 | 15 | public void run() 16 | { 17 | const int NUM_THREADS = 16; 18 | 19 | counter = 0; 20 | 21 | var lstTh = new List(); 22 | 23 | for (int i = 0; i < NUM_THREADS; ++i) 24 | { 25 | lstTh.Add(new Thread(doTask)); 26 | } 27 | 28 | lstTh.ForEach(th => th.Start()); 29 | lstTh.ForEach(th => th.Join()); 30 | 31 | Console.WriteLine("counter = " + counter); 32 | // We are NOT sure that counter = 16000 33 | } 34 | 35 | 36 | private void doTask() 37 | { 38 | Thread.Sleep(1000); 39 | 40 | for (int i = 0; i < 1000; ++i) 41 | ++counter; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /csharp/demo/demo12c02-race-cond-data-race.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * RACE CONDITIONS AND DATA RACES 3 | */ 4 | using System; 5 | using System.Threading; 6 | 7 | 8 | 9 | class Demo12C02 : IRunnable 10 | { 11 | public void run() 12 | { 13 | var thA = new Thread(() => 14 | { 15 | Thread.Sleep(30); 16 | 17 | while (Global.counter < 10) 18 | ++Global.counter; 19 | 20 | Console.WriteLine("A won !!!"); 21 | }); 22 | 23 | 24 | var thB = new Thread(() => 25 | { 26 | Thread.Sleep(30); 27 | 28 | while (Global.counter > -10) 29 | --Global.counter; 30 | 31 | Console.WriteLine("B won !!!"); 32 | }); 33 | 34 | 35 | thA.Start(); 36 | thB.Start(); 37 | } 38 | 39 | 40 | class Global 41 | { 42 | public static int counter = 0; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /csharp/demo/demo15a-deadlock.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * DEADLOCK 3 | * Version A 4 | */ 5 | using System; 6 | using System.Threading; 7 | 8 | 9 | 10 | class Demo15A : IRunnable 11 | { 12 | private Mutex mut; 13 | 14 | 15 | public void run() 16 | { 17 | mut = new Mutex(); 18 | 19 | var thFoo = new Thread(() => doTask("foo")); 20 | var thBar = new Thread(() => doTask("bar")); 21 | 22 | thFoo.Start(); 23 | thBar.Start(); 24 | 25 | thFoo.Join(); 26 | thBar.Join(); 27 | 28 | // The app may throw System.Threading.AbandonedMutexException 29 | Console.WriteLine("You will never see this statement due to deadlock!"); 30 | } 31 | 32 | 33 | private void doTask(string name) 34 | { 35 | mut.WaitOne(); 36 | 37 | Console.WriteLine(name + " acquired resource"); 38 | 39 | // mut.ReleaseMutex(); // Forget this statement ==> deadlock 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /csharp/demo/demo17a-reentrant-lock.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * REENTRANT LOCKS (RECURSIVE MUTEXES) 3 | * 4 | * In C#, "lock" keyword and System.Threading.Monitor class allow re-entrancy. 5 | * That means they are reentrant locks by default. 6 | * 7 | * Version A: A simple example 8 | */ 9 | using System; 10 | using System.Threading; 11 | 12 | 13 | 14 | class Demo17A : IRunnable 15 | { 16 | public void run() 17 | { 18 | const string resource = "resource"; 19 | 20 | new Thread(() => 21 | { 22 | lock (resource) 23 | { 24 | Console.WriteLine("First time acquiring the resource"); 25 | 26 | lock (resource) 27 | { 28 | Console.WriteLine("Second time acquiring the resource"); 29 | } 30 | } 31 | }).Start(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /csharp/demo/demo21a03-condition-variable.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * CONDITION VARIABLES 3 | */ 4 | using System; 5 | using System.Threading; 6 | 7 | 8 | 9 | class Demo21A03 : IRunnable 10 | { 11 | public void run() 12 | { 13 | var conditionVar = new object(); 14 | 15 | ThreadStart foo = () => 16 | { 17 | Console.WriteLine("foo is waiting..."); 18 | 19 | lock (conditionVar) 20 | { 21 | Monitor.Wait(conditionVar); 22 | } 23 | 24 | Console.WriteLine("foo resumed"); 25 | }; 26 | 27 | ThreadStart bar = () => 28 | { 29 | Thread.Sleep(3000); 30 | 31 | lock (conditionVar) 32 | { 33 | // Notify all waiting threads 34 | Monitor.PulseAll(conditionVar); 35 | } 36 | }; 37 | 38 | for (int i = 0; i < 3; ++i) 39 | new Thread(foo).Start(); 40 | 41 | new Thread(bar).Start(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /csharp/demo/demo24-volatile.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * THE VOLATILE KEYWORD 3 | */ 4 | using System; 5 | using System.Threading; 6 | 7 | 8 | 9 | class Demo24 : IRunnable 10 | { 11 | public void run() 12 | { 13 | Global.isRunning = true; 14 | new Thread(doTask).Start(); 15 | 16 | Thread.Sleep(6000); 17 | Global.isRunning = false; 18 | } 19 | 20 | 21 | private void doTask() 22 | { 23 | while (Global.isRunning) 24 | { 25 | Console.WriteLine("Running..."); 26 | Thread.Sleep(2000); 27 | } 28 | } 29 | 30 | 31 | class Global 32 | { 33 | public static volatile bool isRunning; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /csharp/demo/demo25a-atomic.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * ATOMIC ACCESS 3 | */ 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Threading; 7 | 8 | 9 | 10 | class Demo25A : IRunnable 11 | { 12 | public void run() 13 | { 14 | ThreadStart doTask = () => 15 | { 16 | Thread.Sleep(1000); 17 | Global.counter += 1; 18 | }; 19 | 20 | 21 | var lstTh = new List(); 22 | 23 | for (int i = 0; i < 1000; ++i) 24 | lstTh.Add(new Thread(doTask)); 25 | 26 | 27 | lstTh.ForEach(th => th.Start()); 28 | lstTh.ForEach(th => th.Join()); 29 | 30 | 31 | // Unpredictable result 32 | Console.WriteLine("counter = " + Global.counter); 33 | } 34 | 35 | 36 | class Global 37 | { 38 | public static volatile int counter = 0; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /csharp/demo/demo25b-atomic.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * ATOMIC ACCESS 3 | */ 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Threading; 7 | 8 | 9 | 10 | class Demo25B : IRunnable 11 | { 12 | public void run() 13 | { 14 | ThreadStart doTask = () => 15 | { 16 | Thread.Sleep(1000); 17 | Interlocked.Increment(ref Global.counter); 18 | }; 19 | 20 | 21 | var lstTh = new List(); 22 | 23 | for (int i = 0; i < 1000; ++i) 24 | lstTh.Add(new Thread(doTask)); 25 | 26 | 27 | lstTh.ForEach(th => th.Start()); 28 | lstTh.ForEach(th => th.Join()); 29 | 30 | 31 | // counter = 1000 32 | Console.WriteLine("counter = " + Global.counter); 33 | } 34 | 35 | 36 | class Global 37 | { 38 | public static volatile int counter = 0; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /csharp/demoex/demoex-async-future-a01.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * ASYNCHRONOUS PROGRAMMING WITH THE FUTURE/TASK 3 | */ 4 | using System; 5 | using System.Threading.Tasks; 6 | #pragma warning disable CS1998 7 | 8 | 9 | 10 | class DemoExAsyncA01 : IRunnable 11 | { 12 | public async void run() 13 | { 14 | var task = doSomething("cleaning house"); 15 | 16 | while (false == task.IsCompleted) 17 | { 18 | // Waiting... 19 | } 20 | } 21 | 22 | 23 | private async Task doSomething(string taskName) 24 | 25 | { 26 | Console.WriteLine("I am doing " + taskName); 27 | } 28 | } 29 | 30 | 31 | 32 | #pragma warning restore CS1998 33 | -------------------------------------------------------------------------------- /csharp/demoex/demoex-async-future-a02.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * ASYNCHRONOUS PROGRAMMING WITH THE FUTURE/TASK 3 | */ 4 | using System; 5 | using System.Threading.Tasks; 6 | #pragma warning disable CS1998 7 | 8 | 9 | 10 | class DemoExAsyncA02 : IRunnable 11 | { 12 | public async void run() 13 | { 14 | var task = getSquared(7); 15 | 16 | while (false == task.IsCompleted) 17 | { 18 | // Waiting... 19 | } 20 | 21 | int result = await task; 22 | Console.WriteLine(result); 23 | } 24 | 25 | 26 | 27 | private async Task getSquared(int x) 28 | 29 | { 30 | return x * x; 31 | } 32 | } 33 | 34 | 35 | 36 | #pragma warning restore CS1998 37 | -------------------------------------------------------------------------------- /csharp/demoex/demoex-async-future-a03.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * ASYNCHRONOUS PROGRAMMING WITH THE FUTURE/TASK 3 | */ 4 | using System; 5 | using System.Threading.Tasks; 6 | #pragma warning disable CS1998 7 | 8 | 9 | 10 | class DemoExAsyncA03 : IRunnable 11 | { 12 | public async void run() 13 | { 14 | var task = getSquared(7); 15 | 16 | // Waiting for task completion 17 | task.Wait(); 18 | 19 | int result = await task; 20 | Console.WriteLine(result); 21 | } 22 | 23 | private async Task getSquared(int x) 24 | { 25 | return x * x; 26 | } 27 | } 28 | 29 | 30 | 31 | #pragma warning restore CS1998 32 | -------------------------------------------------------------------------------- /csharp/demoex/demoex-async-future-a04.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * ASYNCHRONOUS PROGRAMMING WITH THE FUTURE/TASK 3 | */ 4 | using System; 5 | using System.Threading.Tasks; 6 | 7 | 8 | 9 | class DemoExAsyncA04 : IRunnable 10 | { 11 | public async void run() 12 | { 13 | var task = cookEggs(); 14 | 15 | // Waiting for task completion 16 | task.Wait(); 17 | 18 | string result = await task; 19 | Console.WriteLine(result); 20 | } 21 | 22 | private async Task cookEggs() 23 | { 24 | Console.WriteLine("I am cooking eggs"); 25 | 26 | // Cooking eggs in 2 seconds 27 | await Task.Delay(2000); 28 | 29 | /* 30 | * Avoid using System.Threading.Thread.Sleep(2000) 31 | * Because one thread can work on multiple tasks at once. 32 | * 33 | * Thread.Sleep pauses current thread. 34 | * Task.Delay pauses current task. 35 | */ 36 | 37 | return "fried eggs"; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /csharp/demoex/demoex-async-future-a05.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * ASYNCHRONOUS PROGRAMMING WITH THE FUTURE/TASK 3 | */ 4 | using System; 5 | using System.Threading.Tasks; 6 | 7 | 8 | 9 | class DemoExAsyncA05 : IRunnable 10 | { 11 | public void run() 12 | { 13 | var task = cookEggs(); 14 | 15 | /* 16 | * By calling property "Task.Result", app should wait if necessary for the computation to complete 17 | * and then retrieves its result. 18 | * 19 | * So, we can omit the statement "task.Wait()" 20 | */ 21 | 22 | string result = task.Result; 23 | Console.WriteLine(result); 24 | } 25 | 26 | private async Task cookEggs() 27 | { 28 | Console.WriteLine("I am cooking eggs"); 29 | 30 | // Cooking eggs in 2 seconds 31 | await Task.Delay(2000); 32 | 33 | return "fried eggs"; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /csharp/demoex/demoex-async-future-c01.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * ASYNCHRONOUS PROGRAMMING WITH THE FUTURE/TASK 3 | */ 4 | using System; 5 | using System.Threading.Tasks; 6 | 7 | 8 | 9 | class DemoExAsyncC01 : IRunnable 10 | { 11 | public void run() 12 | { 13 | var task = getSquared(7) 14 | .ContinueWith((previousTask) => getDiv2(previousTask.Result)) 15 | .Unwrap(); 16 | 17 | int result = task.Result; 18 | Console.WriteLine(result); 19 | } 20 | 21 | private async Task getSquared(int x) 22 | { 23 | await Task.Delay(100); 24 | return x * x; 25 | } 26 | 27 | private async Task getDiv2(int x) 28 | { 29 | await Task.Delay(100); 30 | return x / 2; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /csharp/demoex/demoex-async-future-c02.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * ASYNCHRONOUS PROGRAMMING WITH THE FUTURE/TASK 3 | */ 4 | using System; 5 | using System.Threading.Tasks; 6 | 7 | 8 | 9 | class DemoExAsyncC02 : IRunnable 10 | { 11 | public void run() 12 | { 13 | var task = getSquared(7) 14 | .ContinueWith((previousTask) => getDiv2(previousTask.Result)) 15 | .Unwrap() 16 | .ContinueWith((previousTask) => Console.WriteLine(previousTask.Result)); 17 | 18 | task.Wait(); 19 | } 20 | 21 | private async Task getSquared(int x) 22 | { 23 | await Task.Delay(100); 24 | return x * x; 25 | } 26 | 27 | private async Task getDiv2(int x) 28 | { 29 | await Task.Delay(100); 30 | return x / 2; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /csharp/multithreading.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /java/.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | /build/ 3 | /dist/ 4 | .classpath 5 | .project 6 | -------------------------------------------------------------------------------- /java/README.md: -------------------------------------------------------------------------------- 1 | # JAVA MULTITHREADING 2 | 3 | ## DESCRIPTION 4 | 5 | Multithreading in Java. 6 | 7 | ## PROJECT SPECIFICATIONS 8 | 9 | WARNING: Java-17 features. 10 | -------------------------------------------------------------------------------- /java/src/demo00_intro/App.java: -------------------------------------------------------------------------------- 1 | /* 2 | * INTRODUCTION TO MULTITHREADING 3 | * You should try running this app several times and see results. 4 | */ 5 | 6 | package demo00_intro; 7 | 8 | 9 | 10 | public class App { 11 | 12 | public static void main(String[] args) { 13 | Thread th = new ExampleThread(); 14 | 15 | th.start(); 16 | 17 | for (int i = 0; i < 300; ++i) 18 | System.out.print("A"); 19 | } 20 | 21 | } 22 | 23 | 24 | 25 | class ExampleThread extends Thread { 26 | @Override 27 | public void run() { 28 | for (int i = 0; i < 300; ++i) 29 | System.out.print("B"); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /java/src/demo01_hello/AppA01.java: -------------------------------------------------------------------------------- 1 | /* 2 | * HELLO WORLD VERSION MULTITHREADING 3 | * Version A01: Using class Thread (original way) 4 | */ 5 | 6 | package demo01_hello; 7 | 8 | 9 | 10 | public class AppA01 { 11 | 12 | public static void main(String[] args) throws InterruptedException { 13 | var th = new ExampleThread(); 14 | th.start(); 15 | System.out.println("Hello from main thread"); 16 | } 17 | 18 | } 19 | 20 | 21 | 22 | class ExampleThread extends Thread { 23 | @Override 24 | public void run() { 25 | System.out.println("Hello from example thread"); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /java/src/demo01_hello/AppA02.java: -------------------------------------------------------------------------------- 1 | /* 2 | * HELLO WORLD VERSION MULTITHREADING 3 | * Version A02: Using class Thread (anonymous subclass) 4 | */ 5 | 6 | package demo01_hello; 7 | 8 | 9 | 10 | public class AppA02 { 11 | 12 | public static void main(String[] args) throws InterruptedException { 13 | var th = new Thread() { 14 | @Override 15 | public void run() { 16 | System.out.println("Hello from example thread"); 17 | } 18 | }; 19 | 20 | th.start(); 21 | 22 | System.out.println("Hello from main thread"); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /java/src/demo01_hello/AppB01.java: -------------------------------------------------------------------------------- 1 | /* 2 | * HELLO WORLD VERSION MULTITHREADING 3 | * Version B01: Using inteface Runnable 4 | */ 5 | 6 | package demo01_hello; 7 | 8 | 9 | 10 | public class AppB01 { 11 | 12 | public static void main(String[] args) throws InterruptedException { 13 | var doTask = new ExampleRunnable(); 14 | 15 | var th1 = new Thread(doTask); 16 | var th2 = new Thread(doTask); 17 | 18 | th1.start(); 19 | th2.start(); 20 | 21 | System.out.println("Hello from main thread"); 22 | } 23 | 24 | } 25 | 26 | 27 | 28 | class ExampleRunnable implements Runnable { 29 | @Override 30 | public void run() { 31 | System.out.println("Hello from example thread"); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /java/src/demo01_hello/AppB02.java: -------------------------------------------------------------------------------- 1 | /* 2 | * HELLO WORLD VERSION MULTITHREADING 3 | * Version B02: Using inteface Runnable with lambdas 4 | */ 5 | 6 | package demo01_hello; 7 | 8 | 9 | 10 | public class AppB02 { 11 | 12 | public static void main(String[] args) throws InterruptedException { 13 | Runnable doTask = () -> System.out.println("Hello from example thread"); 14 | 15 | var th1 = new Thread(doTask); 16 | var th2 = new Thread(doTask); 17 | 18 | th1.start(); 19 | th2.start(); 20 | 21 | System.out.println("Hello from main thread"); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /java/src/demo01_hello/AppB03.java: -------------------------------------------------------------------------------- 1 | /* 2 | * HELLO WORLD VERSION MULTITHREADING 3 | * Version B03: Using inteface Runnable with lambdas 4 | */ 5 | 6 | package demo01_hello; 7 | 8 | 9 | 10 | public class AppB03 { 11 | 12 | public static void main(String[] args) throws InterruptedException { 13 | var th = new Thread(() -> System.out.println("Hello from example thread")); 14 | 15 | th.start(); 16 | 17 | System.out.println("Hello from main thread"); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /java/src/demo01_hello/AppC01.java: -------------------------------------------------------------------------------- 1 | /* 2 | * HELLO WORLD VERSION MULTITHREADING 3 | * Version C01: Using functions (via delegation from lambdas) 4 | */ 5 | 6 | package demo01_hello; 7 | 8 | 9 | 10 | public class AppC01 { 11 | 12 | public static void main(String[] args) throws InterruptedException { 13 | var th = new Thread(() -> doTask()); 14 | 15 | th.start(); 16 | 17 | System.out.println("Hello from main thread"); 18 | } 19 | 20 | 21 | private static void doTask() { 22 | System.out.println("Hello from example thread"); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /java/src/demo01_hello/AppC02.java: -------------------------------------------------------------------------------- 1 | /* 2 | * HELLO WORLD VERSION MULTITHREADING 3 | * Version C02: Using function references 4 | */ 5 | 6 | package demo01_hello; 7 | 8 | 9 | 10 | public class AppC02 { 11 | 12 | public static void main(String[] args) throws InterruptedException { 13 | var th = new Thread(AppC02::doTask); 14 | 15 | th.start(); 16 | 17 | System.out.println("Hello from main thread"); 18 | } 19 | 20 | 21 | private static void doTask() { 22 | System.out.println("Hello from example thread"); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /java/src/demo01_hello/AppExtra.java: -------------------------------------------------------------------------------- 1 | /* 2 | * HELLO WORLD VERSION MULTITHREADING 3 | * Version extra: Getting thread name and reference to thread instance executing current thread 4 | */ 5 | 6 | package demo01_hello; 7 | 8 | 9 | 10 | public class AppExtra { 11 | 12 | public static void main(String[] args) throws InterruptedException { 13 | var th = new Thread("Lorem") { 14 | @Override 15 | public void run() { 16 | Thread myself = Thread.currentThread(); // th is myself 17 | 18 | System.out.println("My name is " + this.getName()); // or myself.getName() 19 | System.out.println("My self is " + myself); 20 | } 21 | }; 22 | 23 | th.start(); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /java/src/demo02_join/AppA.java: -------------------------------------------------------------------------------- 1 | /* 2 | * THREAD JOINS 3 | */ 4 | 5 | package demo02_join; 6 | 7 | 8 | 9 | public class AppA { 10 | 11 | public static void main(String[] args) throws InterruptedException { 12 | Thread th = new Thread(() -> doHeavyTask()); 13 | 14 | th.start(); 15 | th.join(); 16 | 17 | System.out.println("Good bye!"); 18 | } 19 | 20 | 21 | @SuppressWarnings("unused") 22 | private static void doHeavyTask() { 23 | // Do a heavy task, which takes a little time 24 | long sum = 0; 25 | for (int i = 0; i < 2000000000; ++i) 26 | sum += i; 27 | 28 | System.out.println("Done!"); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /java/src/demo02_join/AppB.java: -------------------------------------------------------------------------------- 1 | /* 2 | * THREAD JOINS 3 | */ 4 | 5 | package demo02_join; 6 | 7 | 8 | 9 | public class AppB { 10 | 11 | public static void main(String[] args) { 12 | Thread thFoo = new Thread(() -> System.out.println("foo")); 13 | Thread thBar = new Thread(() -> System.out.println("bar")); 14 | 15 | thFoo.start(); 16 | thBar.start(); 17 | 18 | // thFoo.join(); 19 | // thBar.join(); 20 | 21 | /* 22 | * We do not need to call thFoo.join() and thBar.join(). 23 | * The reason is main thread will wait for the completion of all threads before app exits. 24 | */ 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /java/src/demo03_pass_arg/AppA.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PASSING ARGUMENTS 3 | * Version A: Passing arguments to Thread objects 4 | */ 5 | 6 | package demo03_pass_arg; 7 | 8 | 9 | 10 | public class AppA { 11 | 12 | public static void main(String[] args) throws InterruptedException { 13 | var thFoo = new MyThread(1, 2, "red"); 14 | var thBar = new MyThread(3, 4, "blue"); 15 | 16 | thFoo.start(); 17 | thBar.start(); 18 | } 19 | 20 | } 21 | 22 | 23 | 24 | class MyThread extends Thread { 25 | private int a; 26 | private double b; 27 | private String c; 28 | 29 | public MyThread(int a, double b, String c) { 30 | super(); 31 | this.a = a; 32 | this.b = b; 33 | this.c = c; 34 | } 35 | 36 | @Override 37 | public void run() { 38 | System.out.printf("%d %.1f %s %n", a, b, c); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /java/src/demo03_pass_arg/AppB.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PASSING ARGUMENTS 3 | * Version B: Passing arguments to functions 4 | */ 5 | 6 | package demo03_pass_arg; 7 | 8 | 9 | 10 | public class AppB { 11 | 12 | public static void main(String[] args) throws InterruptedException { 13 | var thFoo = new Thread(() -> doTask(1, 2, "red")); 14 | var thBar = new Thread(() -> doTask(3, 4, "blue")); 15 | 16 | thFoo.start(); 17 | thBar.start(); 18 | } 19 | 20 | 21 | private static void doTask(int a, double b, String c) { 22 | System.out.printf("%d %.1f %s %n", a, b, c); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /java/src/demo03_pass_arg/AppC.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PASSING ARGUMENTS 3 | * Version C: Passing arguments by capturing them 4 | * 5 | * Note: The captured variables must be final or effectively final. 6 | */ 7 | 8 | package demo03_pass_arg; 9 | 10 | 11 | 12 | public class AppC { 13 | 14 | public static void main(String[] args) throws InterruptedException { 15 | final int COUNT = 10; 16 | 17 | new Thread(() -> { 18 | 19 | for (int i = 1; i <= COUNT; ++i) 20 | System.out.println("value: " + i); 21 | 22 | }).start(); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /java/src/demo04_sleep/App.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SLEEP 3 | */ 4 | 5 | package demo04_sleep; 6 | 7 | 8 | 9 | public class App { 10 | 11 | public static void main(String[] args) throws InterruptedException { 12 | var thFoo = new Thread(() -> { 13 | System.out.println("foo is sleeping"); 14 | 15 | try { 16 | Thread.sleep(3000); 17 | } catch (InterruptedException e) { 18 | 19 | } 20 | 21 | System.out.println("foo wakes up"); 22 | }); 23 | 24 | 25 | thFoo.start(); 26 | thFoo.join(); 27 | 28 | 29 | System.out.println("Good bye"); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /java/src/demo05_id/App.java: -------------------------------------------------------------------------------- 1 | /* 2 | * GETTING THREAD'S ID 3 | */ 4 | 5 | package demo05_id; 6 | 7 | 8 | 9 | public class App { 10 | 11 | public static void main(String[] args) { 12 | Runnable doTask = () -> { 13 | long id = Thread.currentThread().getId(); 14 | System.out.println(id); 15 | }; 16 | 17 | var thFoo = new Thread(doTask); 18 | var thBar = new Thread(doTask); 19 | 20 | System.out.println("foo's id: " + thFoo.getId()); 21 | System.out.println("bar's id: " + thBar.getId()); 22 | 23 | thFoo.start(); 24 | thBar.start(); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /java/src/demo06_list_threads/AppA.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LIST OF MULTIPLE THREADS 3 | * Version A: Using java.util.List / java.util.ArrayList 4 | */ 5 | 6 | package demo06_list_threads; 7 | 8 | import java.util.ArrayList; 9 | 10 | 11 | 12 | public class AppA { 13 | 14 | public static void main(String[] args) { 15 | final int NUM_THREADS = 5; 16 | 17 | var lstTh = new ArrayList(); 18 | 19 | 20 | for (int i = 0; i < NUM_THREADS; ++i) { 21 | final int index = i; 22 | 23 | lstTh.add(new Thread(() -> { 24 | try { Thread.sleep(500); } 25 | catch (InterruptedException e) { } 26 | 27 | System.out.print(index); 28 | })); 29 | } 30 | 31 | 32 | for (var th : lstTh) 33 | th.start(); 34 | 35 | // We can reduce above for loop with this statement: 36 | // lstTh.forEach(Thread::start); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /java/src/demo06_list_threads/AppB01.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LIST OF MULTIPLE THREADS 3 | * Version B01: Using streams 4 | */ 5 | 6 | package demo06_list_threads; 7 | 8 | import java.util.stream.IntStream; 9 | 10 | 11 | 12 | public class AppB01 { 13 | 14 | public static void main(String[] args) { 15 | var lstTh = IntStream.range(0, 5).mapToObj(i -> new Thread(() -> { 16 | 17 | try { Thread.sleep(500); } 18 | catch (InterruptedException e) { } 19 | 20 | System.out.print(i); 21 | 22 | })).toList(); 23 | 24 | 25 | for (var th : lstTh) 26 | th.start(); 27 | 28 | // We can reduce above for loop with this statement: 29 | // lstTh.forEach(Thread::start); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /java/src/demo06_list_threads/AppB02.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LIST OF MULTIPLE THREADS 3 | * Version B02: Using streams (shorten code, no variable to store list of threads) 4 | */ 5 | 6 | package demo06_list_threads; 7 | 8 | import java.util.stream.IntStream; 9 | 10 | 11 | 12 | public class AppB02 { 13 | 14 | public static void main(String[] args) { 15 | IntStream.range(0, 5).forEach(i -> new Thread(() -> { 16 | 17 | try { Thread.sleep(500); } 18 | catch (InterruptedException e) { } 19 | 20 | System.out.print(i); 21 | 22 | }).start()); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /java/src/demo07_terminate/AppA.java: -------------------------------------------------------------------------------- 1 | /* 2 | * FORCING A THREAD TO TERMINATE (i.e. killing the thread) 3 | * Version A: Interrupting the thread 4 | */ 5 | 6 | package demo07_terminate; 7 | 8 | 9 | 10 | public class AppA { 11 | 12 | public static void main(String[] args) throws InterruptedException { 13 | var th = new Thread(() -> { 14 | while (true) { 15 | System.out.println("Running..."); 16 | 17 | try { Thread.sleep(1000); } 18 | catch (InterruptedException e) { 19 | // Received interrupt signal, now current thread is going to exit 20 | return; 21 | } 22 | } 23 | }); 24 | 25 | 26 | th.start(); 27 | 28 | Thread.sleep(3000); 29 | 30 | th.interrupt(); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /java/src/demo07_terminate/AppB.java: -------------------------------------------------------------------------------- 1 | /* 2 | * FORCING A THREAD TO TERMINATE (i.e. killing the thread) 3 | * Version B: Using a flag to notify the thread 4 | * 5 | * Beside atomic variables, you can use the "volatile" specifier. 6 | */ 7 | 8 | package demo07_terminate; 9 | 10 | import java.util.concurrent.atomic.AtomicBoolean; 11 | 12 | 13 | 14 | public class AppB { 15 | 16 | public static void main(String[] args) throws InterruptedException { 17 | var flagStop = new AtomicBoolean(false); 18 | 19 | var th = new Thread(() -> { 20 | while (true) { 21 | if (flagStop.get()) 22 | break; 23 | 24 | System.out.println("Running..."); 25 | 26 | try { Thread.sleep(1000); } 27 | catch (InterruptedException e) { } 28 | } 29 | }); 30 | 31 | 32 | th.start(); 33 | 34 | Thread.sleep(3000); 35 | 36 | flagStop.set(true); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /java/src/demo08_return_value/AppA.java: -------------------------------------------------------------------------------- 1 | /* 2 | * GETTING RETURNED VALUES FROM THREADS 3 | */ 4 | 5 | package demo08_return_value; 6 | 7 | 8 | 9 | public class AppA { 10 | 11 | public static void main(String[] args) throws InterruptedException { 12 | var thFoo = new MyThread(5); 13 | var thBar = new MyThread(80); 14 | 15 | thFoo.start(); 16 | thBar.start(); 17 | 18 | thFoo.join(); 19 | thBar.join(); 20 | 21 | System.out.println(thFoo.result); 22 | System.out.println(thBar.result); 23 | } 24 | 25 | } 26 | 27 | 28 | 29 | class MyThread extends Thread { 30 | public int arg = 0; 31 | public int result = 0; 32 | 33 | public MyThread(int arg) { 34 | super(); 35 | this.arg = arg; 36 | } 37 | 38 | @Override 39 | public void run() { 40 | result = arg * 2; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /java/src/demo08_return_value/AppB.java: -------------------------------------------------------------------------------- 1 | /* 2 | * GETTING RETURNED VALUES FROM THREADS 3 | */ 4 | 5 | package demo08_return_value; 6 | 7 | 8 | 9 | public class AppB { 10 | 11 | public static void main(String[] args) throws InterruptedException { 12 | int[] result = new int[2]; 13 | 14 | var thFoo = new Thread(() -> result[0] = doubleValue(5)); 15 | var thBar = new Thread(() -> result[1] = doubleValue(80)); 16 | 17 | thFoo.start(); 18 | thBar.start(); 19 | 20 | // Wait until thFoo and thBar finish 21 | thFoo.join(); 22 | thBar.join(); 23 | 24 | System.out.println(result[0]); 25 | System.out.println(result[1]); 26 | } 27 | 28 | 29 | private static int doubleValue(int value) { 30 | return value * 2; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /java/src/demo09_detach/App.java: -------------------------------------------------------------------------------- 1 | /* 2 | * THREAD DETACHING 3 | */ 4 | 5 | package demo09_detach; 6 | 7 | 8 | 9 | public class App { 10 | 11 | public static void main(String[] args) throws InterruptedException { 12 | var thFoo = new Thread(() -> { 13 | System.out.println("foo is starting..."); 14 | 15 | try { Thread.sleep(2000); } catch (InterruptedException e) { } 16 | 17 | System.out.println("foo is exiting..."); 18 | }); 19 | 20 | 21 | thFoo.setDaemon(true); 22 | thFoo.start(); 23 | 24 | 25 | // If I comment this statement, 26 | // thFoo will be forced into terminating with main thread 27 | Thread.sleep(3000); 28 | 29 | 30 | System.out.println("Main thread is exiting"); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /java/src/demo10_yield/App.java: -------------------------------------------------------------------------------- 1 | /* 2 | * THREAD YIELDING 3 | */ 4 | 5 | package demo10_yield; 6 | 7 | import java.time.Duration; 8 | import java.time.Instant; 9 | 10 | 11 | 12 | public class App { 13 | 14 | public static void main(String[] args) { 15 | var tpStartMeasure = Instant.now(); 16 | 17 | littleSleep(130000); 18 | 19 | var timeElapsed = Duration.between(tpStartMeasure, Instant.now()); 20 | 21 | System.out.println("Elapsed time: " + timeElapsed.toNanos() + " nanoseonds"); 22 | } 23 | 24 | 25 | private static void littleSleep(int ns) { 26 | var tpStart = Instant.now(); 27 | var tpEnd = tpStart.plusNanos(ns); 28 | 29 | do { 30 | Thread.yield(); 31 | } 32 | while (Instant.now().isBefore(tpEnd)); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /java/src/demo11_exec_service/AppA.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EXECUTOR SERVICES AND THREAD POOLS 3 | * Version A: The executor service (of which thread pool) containing a single thread 4 | * 5 | * Note: The single thread executor is ideal for creating an event loop. 6 | */ 7 | 8 | package demo11_exec_service; 9 | 10 | import java.util.concurrent.ExecutorService; 11 | import java.util.concurrent.Executors; 12 | 13 | 14 | 15 | public class AppA { 16 | 17 | public static void main(String[] args) { 18 | ExecutorService executor = Executors.newSingleThreadExecutor(); 19 | 20 | executor.submit(() -> System.out.println("Hello World")); 21 | executor.submit(() -> System.out.println("Hello Multithreading")); 22 | 23 | Runnable rnn = () -> System.out.println("Hello the Executor Service"); 24 | executor.submit(rnn); 25 | 26 | executor.shutdown(); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /java/src/demo11_exec_service/AppC02.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EXECUTOR SERVICES AND THREAD POOLS 3 | * Version C02: The executor service and Future objects - Getting started 4 | */ 5 | 6 | package demo11_exec_service; 7 | 8 | import java.util.concurrent.ExecutionException; 9 | import java.util.concurrent.ExecutorService; 10 | import java.util.concurrent.Executors; 11 | import java.util.concurrent.Future; 12 | 13 | 14 | 15 | public class AppC02 { 16 | 17 | public static void main(String[] args) throws InterruptedException, ExecutionException { 18 | ExecutorService executor = Executors.newSingleThreadExecutor(); 19 | 20 | Future task = executor.submit(() -> getSquared(7)); 21 | 22 | executor.shutdown(); 23 | 24 | while (false == task.isDone()) { 25 | // Waiting... 26 | } 27 | 28 | Integer result = task.get(); 29 | System.out.println(result); 30 | } 31 | 32 | 33 | private static int getSquared(int x) { 34 | return x * x; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /java/src/demo12_race_condition/AppA.java: -------------------------------------------------------------------------------- 1 | /* 2 | * RACE CONDITIONS 3 | */ 4 | 5 | package demo12_race_condition; 6 | 7 | import java.util.stream.IntStream; 8 | 9 | 10 | 11 | public class AppA { 12 | 13 | public static void main(String[] args) { 14 | final int NUM_THREADS = 4; 15 | 16 | 17 | var lstTh = IntStream.range(0, NUM_THREADS) 18 | .mapToObj(i -> new Thread(() -> { 19 | try { Thread.sleep(1000); } catch (InterruptedException e) { } 20 | System.out.print(i); 21 | })) 22 | .toList(); 23 | 24 | 25 | lstTh.forEach(Thread::start); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /java/src/demo12_race_condition/AppB01.java: -------------------------------------------------------------------------------- 1 | /* 2 | * DATA RACES 3 | * Version 01: Without multithreading 4 | */ 5 | 6 | package demo12_race_condition; 7 | 8 | import java.util.Arrays; 9 | 10 | 11 | 12 | public class AppB01 { 13 | 14 | public static void main(String[] args) { 15 | final int N = 8; 16 | int result = getResult(N); 17 | System.out.println("Number of integers that are divisible by 2 or 3 is: " + result); 18 | } 19 | 20 | 21 | private static int getResult(int N) { 22 | var a = new boolean[N + 1]; 23 | Arrays.fill(a, false); 24 | 25 | for (int i = 1; i <= N; ++i) 26 | if (i % 2 == 0 || i % 3 == 0) 27 | a[i] = true; 28 | 29 | int res = countTrue(a, N); 30 | return res; 31 | } 32 | 33 | 34 | private static int countTrue(boolean[] a, int N) { 35 | int count = 0; 36 | 37 | for (int i = 1; i <= N; ++i) 38 | if (a[i]) 39 | ++count; 40 | 41 | return count; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /java/src/demo12_race_condition/AppC02.java: -------------------------------------------------------------------------------- 1 | /* 2 | * RACE CONDITIONS AND DATA RACES 3 | */ 4 | 5 | package demo12_race_condition; 6 | 7 | 8 | 9 | public class AppC02 { 10 | 11 | public static void main(String[] args) throws InterruptedException { 12 | var thA = new Thread(() -> { 13 | try { Thread.sleep(1000); } catch (InterruptedException e) { } 14 | 15 | while (Global.counter < 10) 16 | ++Global.counter; 17 | 18 | System.out.println("A won !!!"); 19 | }); 20 | 21 | 22 | var thB = new Thread(() -> { 23 | try { Thread.sleep(1000); } catch (InterruptedException e) { } 24 | 25 | while (Global.counter > -10) 26 | --Global.counter; 27 | 28 | System.out.println("B won !!!"); 29 | }); 30 | 31 | 32 | thA.start(); 33 | thB.start(); 34 | } 35 | 36 | 37 | 38 | private static class Global { 39 | public static int counter = 0; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /java/src/demo13_mutex/AppA.java: -------------------------------------------------------------------------------- 1 | /* 2 | * MUTEXES 3 | */ 4 | 5 | package demo13_mutex; 6 | 7 | 8 | 9 | public class AppA { 10 | 11 | public static void main(String[] args) { 12 | /* 13 | * Unfortunately, Java does not support the mutex feature by default. 14 | * You can use a binary semaphore as a mutex. 15 | */ 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /java/src/demo17_reentrant_lock/AppA01.java: -------------------------------------------------------------------------------- 1 | /* 2 | * REENTRANT LOCKS (RECURSIVE MUTEXES) 3 | * Version A01: A simple example 4 | */ 5 | 6 | package demo17_reentrant_lock; 7 | 8 | import java.util.concurrent.locks.Lock; 9 | import java.util.concurrent.locks.ReentrantLock; 10 | 11 | 12 | 13 | public class AppA01 { 14 | 15 | public static void main(String[] args) { 16 | Lock lk = new ReentrantLock(); 17 | 18 | 19 | new Thread(() -> { 20 | 21 | lk.lock(); 22 | System.out.println("First time acquiring the resource"); 23 | 24 | lk.lock(); 25 | System.out.println("Second time acquiring the resource"); 26 | 27 | lk.unlock(); 28 | lk.unlock(); 29 | 30 | }).start(); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /java/src/demo17_reentrant_lock/AppB01.java: -------------------------------------------------------------------------------- 1 | /* 2 | * REENTRANT LOCKS (RECURSIVE MUTEXES) 3 | * Version B01: A simple example 4 | * 5 | * Looking into the lock behind the "synchronized" keyword. 6 | * The lock behind the synchronized methods and blocks is reentrant lock. 7 | * That is, the current thread can acquire the same synchronized lock over and over again while holding it. 8 | */ 9 | 10 | package demo17_reentrant_lock; 11 | 12 | 13 | 14 | public class AppB01 { 15 | 16 | public static void main(String[] args) { 17 | final Object resource = "resource"; 18 | 19 | 20 | new Thread(() -> { 21 | synchronized (resource) { 22 | System.out.println("First time acquiring the resource"); 23 | 24 | synchronized (resource) { 25 | System.out.println("Second time acquiring the resource"); 26 | } 27 | } 28 | }).start(); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /java/src/demo23_thread_local/AppA02.java: -------------------------------------------------------------------------------- 1 | /* 2 | * THREAD-LOCAL STORAGE 3 | * Introduction 4 | * 5 | * Use ThreadLocal.withInitial for better initialization. 6 | */ 7 | 8 | package demo23_thread_local; 9 | 10 | 11 | 12 | public class AppA02 { 13 | 14 | public static void main(String[] args) { 15 | // Main thread sets value = "APPLE" 16 | MyTask.set("APPLE"); 17 | System.out.println(MyTask.get()); 18 | 19 | 20 | // Child thread gets value 21 | // Expected output: "NOT SET" 22 | new Thread(() -> { 23 | System.out.println(MyTask.get()); 24 | }).start(); 25 | } 26 | 27 | 28 | 29 | private static class MyTask { 30 | private static final ThreadLocal data 31 | = ThreadLocal.withInitial(() -> "NOT SET"); 32 | 33 | public static String get() { 34 | return data.get(); 35 | } 36 | 37 | public static void set(String value) { 38 | data.set(value); 39 | } 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /java/src/demo24_volatile/App.java: -------------------------------------------------------------------------------- 1 | /* 2 | * THE VOLATILE KEYWORD 3 | */ 4 | 5 | package demo24_volatile; 6 | 7 | 8 | 9 | public class App { 10 | 11 | public static void main(String[] args) throws InterruptedException { 12 | Global.isRunning = true; 13 | new Thread(() -> doTask()).start(); 14 | 15 | Thread.sleep(6000); 16 | Global.isRunning = false; 17 | } 18 | 19 | 20 | private static void doTask() { 21 | while (Global.isRunning) { 22 | System.out.println("Running..."); 23 | try { Thread.sleep(2000); } catch (InterruptedException e) { } 24 | } 25 | } 26 | 27 | 28 | 29 | private static class Global { 30 | public static volatile boolean isRunning; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /java/src/demo25_atomic/AppA.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ATOMIC ACCESS 3 | */ 4 | 5 | package demo25_atomic; 6 | 7 | import java.util.stream.IntStream; 8 | 9 | 10 | 11 | public class AppA { 12 | 13 | public static void main(String[] args) throws InterruptedException { 14 | Runnable doTask = () -> { 15 | try { Thread.sleep(1000); } catch (InterruptedException e) { } 16 | Global.counter += 1; 17 | }; 18 | 19 | 20 | var lstTh = IntStream.range(0, 1000).mapToObj(i -> new Thread(doTask)).toList(); 21 | 22 | 23 | for (var th : lstTh) 24 | th.start(); 25 | 26 | for (var th : lstTh) 27 | th.join(); 28 | 29 | 30 | // Unpredictable result 31 | System.out.println("counter = " + Global.counter); 32 | } 33 | 34 | 35 | 36 | private static class Global { 37 | public static volatile int counter = 0; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /java/src/demo25_atomic/AppB.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ATOMIC ACCESS 3 | */ 4 | 5 | package demo25_atomic; 6 | 7 | import java.util.concurrent.atomic.AtomicInteger; 8 | import java.util.stream.IntStream; 9 | 10 | 11 | 12 | public class AppB { 13 | 14 | public static void main(String[] args) throws InterruptedException { 15 | Runnable doTask = () -> { 16 | try { Thread.sleep(1000); } catch (InterruptedException e) { } 17 | Global.counter.incrementAndGet(); 18 | // Global.counter.addAndGet(1); 19 | }; 20 | 21 | 22 | var lstTh = IntStream.range(0, 1000).mapToObj(i -> new Thread(doTask)).toList(); 23 | 24 | 25 | for (var th : lstTh) 26 | th.start(); 27 | 28 | for (var th : lstTh) 29 | th.join(); 30 | 31 | 32 | // counter = 1000 33 | System.out.println("counter = " + Global.counter); 34 | } 35 | 36 | 37 | 38 | private static class Global { 39 | public static AtomicInteger counter = new AtomicInteger(0); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /java/src/demoex/async/AppA.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ASYNCHRONOUS PROGRAMMING WITH THE FUTURE/TASK 3 | */ 4 | 5 | package demoex.async; 6 | 7 | 8 | 9 | public class AppA { 10 | 11 | public static void main(String[] args) { 12 | System.out.println("Please review demo: Thread pool, version C"); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /java/src/demoex/async/AppC02.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ASYNCHRONOUS PROGRAMMING WITH THE FUTURE/TASK 3 | */ 4 | 5 | package demoex.async; 6 | 7 | import java.util.concurrent.CompletableFuture; 8 | import java.util.concurrent.ExecutionException; 9 | 10 | 11 | 12 | public class AppC02 { 13 | 14 | public static void main(String[] args) throws InterruptedException, ExecutionException { 15 | CompletableFuture task; 16 | 17 | task = CompletableFuture 18 | .supplyAsync(() -> getSquared(7)) 19 | .thenApply(AppC02::getDiv2) 20 | .thenAccept(System.out::println); 21 | 22 | task.get(); 23 | } 24 | 25 | 26 | private static int getSquared(int x) { 27 | return x * x; 28 | } 29 | 30 | 31 | private static int getDiv2(int x) { 32 | return x / 2; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /js-nodejs/.gitignore: -------------------------------------------------------------------------------- 1 | /package-lock.json 2 | /node_modules/ -------------------------------------------------------------------------------- /js-nodejs/demo00.js: -------------------------------------------------------------------------------- 1 | /* 2 | INTRODUCTION TO MULTITHREADING 3 | You should try running this app several times and see results. 4 | */ 5 | 6 | import * as mylib from './mylib.js'; 7 | import { Worker, isMainThread } from 'worker_threads'; 8 | 9 | 10 | const workerFunc = async () => { 11 | for (let i = 0; i < 300; ++i) { 12 | await mylib.sleep(1); 13 | process.stdout.write('B'); 14 | } 15 | }; 16 | 17 | 18 | const mainFunc = async () => { 19 | const worker = new Worker(new URL(import.meta.url)); 20 | 21 | for (let i = 0; i < 300; ++i) { 22 | await mylib.sleep(1); 23 | process.stdout.write('A'); 24 | } 25 | }; 26 | 27 | 28 | if (isMainThread) { 29 | await mainFunc(); 30 | } else { 31 | await workerFunc(); 32 | } 33 | -------------------------------------------------------------------------------- /js-nodejs/demo01a-hello.js: -------------------------------------------------------------------------------- 1 | /* 2 | HELLO WORLD VERSION MULTITHREADING 3 | Version A: Using the same source code file for both main thread and worker thread 4 | */ 5 | 6 | import { Worker, isMainThread } from 'worker_threads'; 7 | 8 | 9 | //--------------------------------------------- 10 | // WORKER THREAD SECTION 11 | //--------------------------------------------- 12 | const workerFunc = () => { 13 | console.log('Hello from example thread'); 14 | }; 15 | 16 | 17 | //--------------------------------------------- 18 | // MAIN THREAD SECTION 19 | //--------------------------------------------- 20 | const mainFunc = () => { 21 | const worker = new Worker(new URL(import.meta.url)); 22 | console.log('Hello from main thread'); 23 | }; 24 | 25 | 26 | if (isMainThread) { 27 | // If this is main thread then execute mainFunc() 28 | mainFunc(); 29 | } else { 30 | // If this is worker thread then execute workerFunc() 31 | workerFunc(); 32 | } 33 | -------------------------------------------------------------------------------- /js-nodejs/demo01b-hello-worker.js: -------------------------------------------------------------------------------- 1 | console.log('Hello from example thread'); 2 | -------------------------------------------------------------------------------- /js-nodejs/demo01b-hello.js: -------------------------------------------------------------------------------- 1 | /* 2 | HELLO WORLD VERSION MULTITHREADING 3 | Version B: Using the individual source code files: 4 | - Main thread: demo01b-hello.js 5 | - Worker thread: demo01b-hello-worker.js 6 | */ 7 | 8 | import * as path from 'path'; 9 | import { Worker, isMainThread } from 'worker_threads'; 10 | 11 | const workerFileName = `./${path.parse(import.meta.url).name}-worker.js`; 12 | const worker = new Worker(workerFileName); 13 | 14 | console.log('Hello from main thread'); 15 | -------------------------------------------------------------------------------- /js-nodejs/demo12b01-data-race-single.js: -------------------------------------------------------------------------------- 1 | /* 2 | DATA RACES 3 | Version 01: Without multithreading 4 | */ 5 | 6 | const getResult = N => { 7 | const a = new Int8Array(N + 1).fill(0); 8 | for (let i = 1; i <= N; ++i) { 9 | if (i % 2 === 0 || i % 3 === 0) 10 | a[i] = 1; 11 | } 12 | const result = a.reduce((x, y) => x + y, 0); 13 | return result; 14 | }; 15 | 16 | 17 | const mainFunc = () => { 18 | const N = 1024; 19 | const result = getResult(N); 20 | console.log('Number of integers that are divisible by 2 or 3 is:', result); 21 | }; 22 | 23 | 24 | mainFunc(); 25 | -------------------------------------------------------------------------------- /js-nodejs/exer01a-max-div.js: -------------------------------------------------------------------------------- 1 | /* 2 | MAXIMUM NUMBER OF DIVISORS 3 | */ 4 | 5 | import * as mylib from './mylib.js'; 6 | 7 | 8 | const mainFunc = () => { 9 | try { 10 | 11 | const RANGE_START = 1; 12 | const RANGE_END = 100000; 13 | 14 | let resValue = 0; 15 | let resNumDiv = 0; 16 | 17 | const tpStart = process.hrtime(); 18 | 19 | for (let i = RANGE_START; i <= RANGE_END; ++i) { 20 | let numDiv = 0; 21 | 22 | for (let j = i / 2; j > 0; --j) 23 | if (i % j == 0) 24 | ++numDiv; 25 | 26 | if (resNumDiv < numDiv) { 27 | resNumDiv = numDiv; 28 | resValue = i; 29 | } 30 | } 31 | 32 | const timeElapsed = mylib.hrtimeToNumber(process.hrtime(tpStart)); 33 | 34 | console.log('The integer which has largest number of divisors is', resValue); 35 | console.log('The largest number of divisor is', resNumDiv); 36 | console.log('Time elapsed =', timeElapsed); 37 | 38 | } catch (error) { 39 | console.error(error); 40 | } 41 | }; 42 | 43 | 44 | mainFunc(); 45 | -------------------------------------------------------------------------------- /js-nodejs/exerex-userhash-util.js: -------------------------------------------------------------------------------- 1 | const { createHash } = await import('node:crypto'); 2 | 3 | 4 | export const getHash = (numLoops, str) => { 5 | for (let i = numLoops; i > 0; --i) { 6 | str = createHash('sha256').update(str).digest('hex'); 7 | } 8 | return str; 9 | }; 10 | 11 | 12 | export const splitStrInToChunks = (numChunks, str) => { 13 | const lstChunks = []; 14 | const quotient = Math.floor(str.length / numChunks); 15 | const remainder = str.length % numChunks; 16 | for (let i = 0; i < numChunks; ++i) { 17 | const chunk = str.substring( 18 | i * quotient + Math.min(i, remainder), 19 | (i+1) * quotient + Math.min(i+1, remainder) 20 | ); 21 | lstChunks.push(chunk); 22 | } 23 | return lstChunks; 24 | }; 25 | -------------------------------------------------------------------------------- /js-nodejs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "dependencies": { 4 | "@types/node": "^18.7.2", 5 | "async-mutex": "^0.3.2", 6 | "express": "^4.18.1", 7 | "piscina": "^3.2.0" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /old/cppstd-ex-thread-pool-deadlock.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thanhit95/multi-threading/9557cdf0f2a6cb0565de4214ded88ede81789162/old/cppstd-ex-thread-pool-deadlock.zip -------------------------------------------------------------------------------- /old/cppstd-reentrant-lock-a.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | REENTRANT LOCK (RECURSIVE MUTEX) 3 | 4 | The function "getFactorial" will cause deadlock. 5 | */ 6 | 7 | 8 | #include 9 | #include 10 | #include 11 | using namespace std; 12 | 13 | 14 | 15 | std::mutex mut; 16 | 17 | 18 | 19 | int getFactorial(int n) { 20 | if (n <= 0) 21 | return 1; 22 | 23 | mut.lock(); 24 | 25 | int result = n * getFactorial(n - 1); 26 | 27 | mut.unlock(); 28 | 29 | return result; 30 | } 31 | 32 | 33 | 34 | void routine(int n) { 35 | int factorial = getFactorial(n); 36 | cout << "Factorial of " << n << " is " << factorial << endl; 37 | } 38 | 39 | 40 | 41 | int main() { 42 | int n = 5; 43 | 44 | auto th = std::thread(routine, n); 45 | 46 | th.join(); 47 | 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /old/cppstd-reentrant-lock-b.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | REENTRANT LOCK (RECURSIVE MUTEX) 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | 13 | std::recursive_mutex mut; 14 | 15 | 16 | 17 | int getFactorial(int n) { 18 | if (n <= 0) 19 | return 1; 20 | 21 | mut.lock(); 22 | 23 | int result = n * getFactorial(n - 1); 24 | 25 | mut.unlock(); 26 | 27 | return result; 28 | } 29 | 30 | 31 | 32 | void routine(int n) { 33 | int factorial = getFactorial(n); 34 | cout << "Factorial of " << n << " is " << factorial << endl; 35 | } 36 | 37 | 38 | 39 | int main() { 40 | int n = 5; 41 | 42 | auto th = std::thread(routine, n); 43 | 44 | th.join(); 45 | 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /python/.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | -------------------------------------------------------------------------------- /python/demo00.py: -------------------------------------------------------------------------------- 1 | ''' 2 | INTRODUCTION TO MULTITHREADING 3 | You should try running this app several times and see results. 4 | ''' 5 | 6 | import threading 7 | 8 | 9 | 10 | def do_task(): 11 | for _ in range(300): 12 | print('B', end='') 13 | 14 | 15 | 16 | th = threading.Thread(target=do_task) 17 | th.start() 18 | 19 | for _ in range(300): 20 | print('A', end='') 21 | 22 | th.join() 23 | print() 24 | -------------------------------------------------------------------------------- /python/demo01_hello.py: -------------------------------------------------------------------------------- 1 | ''' 2 | HELLO WORLD VERSION MULTITHREADING 3 | ''' 4 | 5 | import threading 6 | 7 | 8 | 9 | def do_task(): 10 | print('Hello from example thread') 11 | 12 | 13 | 14 | th = threading.Thread(target=do_task) 15 | th.start() 16 | 17 | print('Hello from main thread') 18 | -------------------------------------------------------------------------------- /python/demo01ex_name.py: -------------------------------------------------------------------------------- 1 | ''' 2 | HELLO WORLD VERSION MULTITHREADING 3 | Getting thread's name 4 | ''' 5 | 6 | import threading 7 | 8 | 9 | 10 | def do_task(): 11 | print(f'My name is {threading.current_thread().name}') 12 | 13 | 14 | 15 | th_foo = threading.Thread(target=do_task, name='foo') 16 | th_bar = threading.Thread(target=do_task, name='bar') 17 | th_foo.start() 18 | th_bar.start() 19 | -------------------------------------------------------------------------------- /python/demo02a_join.py: -------------------------------------------------------------------------------- 1 | ''' 2 | THREAD JOINS 3 | ''' 4 | 5 | import threading 6 | 7 | 8 | 9 | def do_heavy_task(): 10 | # Do a heavy task, which takes a little time 11 | for _ in range(0, 2 * 10**8): 12 | pass 13 | 14 | print('Done!') 15 | 16 | 17 | 18 | th = threading.Thread(target=do_heavy_task) 19 | 20 | th.start() 21 | th.join() 22 | 23 | print('Good bye!') 24 | -------------------------------------------------------------------------------- /python/demo02b_join.py: -------------------------------------------------------------------------------- 1 | ''' 2 | THREAD JOINS 3 | ''' 4 | 5 | import threading 6 | 7 | 8 | 9 | th_foo = threading.Thread(target=lambda:print('foo')) 10 | th_bar = threading.Thread(target=lambda:print('bar')) 11 | 12 | th_foo.start() 13 | th_bar.start() 14 | 15 | # th_foo.join() 16 | # th_bar.join() 17 | 18 | ''' 19 | We do not need to call th_foo.join() and th_bar.join(). 20 | The reason is main thread will wait for the completion of all threads before app exits. 21 | ''' 22 | -------------------------------------------------------------------------------- /python/demo03a_pass_arg.py: -------------------------------------------------------------------------------- 1 | ''' 2 | PASSING ARGUMENTS 3 | Version A: Using the Thread's constructor 4 | ''' 5 | 6 | import threading 7 | 8 | 9 | 10 | def do_task(a: int, b: float, c: str): 11 | print(f'{a} {b} {c}') 12 | 13 | 14 | 15 | th_foo = threading.Thread(target=do_task, args=(1, 2, 'red')) 16 | th_bar = threading.Thread(target=do_task, args=(3, 4, 'blue')) 17 | 18 | th_foo.start() 19 | th_bar.start() 20 | -------------------------------------------------------------------------------- /python/demo03b_pass_arg.py: -------------------------------------------------------------------------------- 1 | ''' 2 | PASSING ARGUMENTS 3 | Version B: Using lambdas 4 | ''' 5 | 6 | import threading 7 | 8 | 9 | 10 | def do_task(a: int, b: float, c: str): 11 | print(f'{a} {b} {c}') 12 | 13 | 14 | 15 | th_foo = threading.Thread(target=lambda:do_task(1, 2, 'red')) 16 | th_bar = threading.Thread(target=lambda:do_task(3, 4, 'blue')) 17 | 18 | th_foo.start() 19 | th_bar.start() 20 | -------------------------------------------------------------------------------- /python/demo04_sleep.py: -------------------------------------------------------------------------------- 1 | ''' 2 | SLEEP 3 | ''' 4 | 5 | import time 6 | import threading 7 | 8 | 9 | 10 | def do_task(): 11 | print('foo is sleeping') 12 | time.sleep(3) 13 | print('foo wakes up') 14 | 15 | 16 | 17 | th_foo = threading.Thread(target=do_task) 18 | 19 | th_foo.start() 20 | th_foo.join() 21 | 22 | print('Good bye') 23 | -------------------------------------------------------------------------------- /python/demo05_id.py: -------------------------------------------------------------------------------- 1 | ''' 2 | GETTING THREAD'S ID 3 | ''' 4 | 5 | import time 6 | import threading 7 | 8 | 9 | 10 | def do_task(): 11 | time.sleep(1) 12 | tid = threading.get_ident() 13 | tid_native = threading.get_native_id() 14 | print('id of current thread:', tid) 15 | print('native id of current thread from operating system:', tid_native) 16 | 17 | 18 | 19 | th_foo = threading.Thread(target=do_task) 20 | th_bar = threading.Thread(target=do_task) 21 | 22 | th_foo.start() 23 | th_bar.start() 24 | 25 | print("foo's id:", th_foo.ident) 26 | print("foo's native id:", th_foo.native_id) 27 | print("bar's id:", th_bar.ident) 28 | print("bar's native id:", th_bar.native_id) 29 | -------------------------------------------------------------------------------- /python/demo06_list_threads.py: -------------------------------------------------------------------------------- 1 | ''' 2 | LIST OF MULTIPLE THREADS 3 | ''' 4 | 5 | import time 6 | import threading 7 | 8 | 9 | 10 | def do_task(index): 11 | time.sleep(0.5) 12 | print(index, end='') 13 | 14 | 15 | 16 | NUM_THREADS = 5 17 | lstth = [] 18 | 19 | for i in range(NUM_THREADS): 20 | lstth.append(threading.Thread( target=do_task, args=(i,) )) 21 | 22 | for th in lstth: 23 | th.start() 24 | -------------------------------------------------------------------------------- /python/demo07_terminate.py: -------------------------------------------------------------------------------- 1 | ''' 2 | FORCING A THREAD TO TERMINATE (i.e. killing the thread) 3 | Using a flag to notify the thread 4 | ''' 5 | 6 | import time 7 | import threading 8 | 9 | 10 | 11 | flag_stop = False 12 | 13 | 14 | 15 | def do_task(): 16 | while True: 17 | if flag_stop: 18 | break 19 | 20 | print('Running...') 21 | time.sleep(1) 22 | 23 | 24 | 25 | th = threading.Thread(target=do_task) 26 | th.start() 27 | 28 | time.sleep(3) 29 | flag_stop = True 30 | -------------------------------------------------------------------------------- /python/demo08a_return_value.py: -------------------------------------------------------------------------------- 1 | ''' 2 | GETTING RETURNED VALUES FROM THREADS 3 | ''' 4 | 5 | import threading 6 | 7 | 8 | 9 | def double_value(value): 10 | return value * 2 11 | 12 | 13 | 14 | res = {} 15 | 16 | th_foo = threading.Thread( target=lambda: res.update({ 'foo': double_value(5) }) ) 17 | th_bar = threading.Thread( target=lambda: res.update({ 'bar': double_value(80) }) ) 18 | 19 | th_foo.start() 20 | th_bar.start() 21 | 22 | # Wait until th_foo and th_far finish 23 | th_foo.join() 24 | th_bar.join() 25 | 26 | print(res['foo']) 27 | print(res['bar']) 28 | -------------------------------------------------------------------------------- /python/demo08b_return_value.py: -------------------------------------------------------------------------------- 1 | ''' 2 | GETTING RETURNED VALUES FROM THREADS 3 | ''' 4 | 5 | import threading 6 | 7 | 8 | 9 | def double_value(result: dict, name: str, value): 10 | result[name] = value * 2 11 | 12 | 13 | 14 | res = {} 15 | 16 | th_foo = threading.Thread( target=double_value, args=(res, 'foo', 5) ) 17 | th_bar = threading.Thread( target=double_value, args=(res, 'bar', 80) ) 18 | 19 | th_foo.start() 20 | th_bar.start() 21 | 22 | # Wait until th_foo and th_far finish 23 | th_foo.join() 24 | th_bar.join() 25 | 26 | print(res['foo']) 27 | print(res['bar']) 28 | -------------------------------------------------------------------------------- /python/demo09_detach.py: -------------------------------------------------------------------------------- 1 | ''' 2 | THREAD DETACHING 3 | ''' 4 | 5 | import time 6 | import threading 7 | 8 | 9 | 10 | def do_task(): 11 | print('foo is starting...') 12 | time.sleep(2) 13 | print('foo is exiting...') 14 | 15 | 16 | 17 | th_foo = threading.Thread(target=do_task, daemon=True) 18 | th_foo.start() 19 | 20 | # If I comment this statement, 21 | # th_foo will be forced into terminating with main thread 22 | time.sleep(3) 23 | 24 | print('Main thread is exiting') 25 | -------------------------------------------------------------------------------- /python/demo10_yield.py: -------------------------------------------------------------------------------- 1 | ''' 2 | THREAD YIELDING 3 | 4 | I think that thread yielding does not make sense in Python. 5 | No demo available. 6 | ''' 7 | -------------------------------------------------------------------------------- /python/demo11a_exec_service.py: -------------------------------------------------------------------------------- 1 | ''' 2 | EXECUTOR SERVICES AND THREAD POOLS 3 | Version A: The executor service (of which thread pool) containing a single thread 4 | ''' 5 | 6 | from concurrent.futures import ThreadPoolExecutor 7 | 8 | 9 | 10 | def do_task(): 11 | print('Hello the Executor Service') 12 | 13 | 14 | 15 | executor = ThreadPoolExecutor(max_workers=1) 16 | 17 | executor.submit(lambda: print('Hello World')) 18 | executor.submit(do_task) 19 | 20 | executor.shutdown(wait=True) 21 | -------------------------------------------------------------------------------- /python/demo11b_exec_service.py: -------------------------------------------------------------------------------- 1 | ''' 2 | EXECUTOR SERVICES AND THREAD POOLS 3 | Version B: The executor service containing multiple threads 4 | ''' 5 | 6 | import time 7 | from concurrent.futures import ThreadPoolExecutor 8 | 9 | 10 | 11 | def do_task(name: str): 12 | print(f'Task {name} is starting') 13 | time.sleep(3) 14 | print(f'Task {name} is completed') 15 | 16 | 17 | 18 | NUM_TASKS = 5 19 | executor = ThreadPoolExecutor(max_workers=2) 20 | 21 | for i in range(NUM_TASKS): 22 | task_name = chr(i + 65) 23 | executor.submit(do_task, task_name) 24 | 25 | executor.shutdown(wait=True) 26 | -------------------------------------------------------------------------------- /python/demo11c01_exec_service.py: -------------------------------------------------------------------------------- 1 | ''' 2 | EXECUTOR SERVICES AND THREAD POOLS 3 | Version C01: The executor service and Future objects 4 | ''' 5 | 6 | from concurrent.futures import ThreadPoolExecutor 7 | 8 | 9 | 10 | def get_squared(x): 11 | return x * x 12 | 13 | 14 | 15 | executor = ThreadPoolExecutor(max_workers=1) 16 | 17 | future = executor.submit(get_squared, 7) 18 | # print(future.done()) 19 | 20 | print(future.result()) 21 | 22 | executor.shutdown(wait=True) 23 | -------------------------------------------------------------------------------- /python/demo11c02_exec_service.py: -------------------------------------------------------------------------------- 1 | ''' 2 | EXECUTOR SERVICES AND THREAD POOLS 3 | Version C02: The executor service and Future objects 4 | ''' 5 | 6 | import time 7 | from concurrent.futures import ThreadPoolExecutor 8 | 9 | 10 | 11 | def get_squared(x): 12 | time.sleep(3) 13 | return x * x 14 | 15 | 16 | 17 | executor = ThreadPoolExecutor(max_workers=1) 18 | 19 | future = executor.submit(get_squared, 7) 20 | 21 | print('Calculating...') 22 | print(future.result()) 23 | 24 | executor.shutdown(wait=True) 25 | -------------------------------------------------------------------------------- /python/demo12a_race_condition.py: -------------------------------------------------------------------------------- 1 | ''' 2 | RACE CONDITIONS 3 | ''' 4 | 5 | import time 6 | import threading 7 | 8 | 9 | 10 | def do_task(index: int): 11 | time.sleep(1) 12 | print(index, end='') 13 | 14 | 15 | 16 | NUM_THREADS = 4 17 | lstth = [] 18 | 19 | for i in range(NUM_THREADS): 20 | lstth.append(threading.Thread( target=do_task, args=(i,) )) 21 | 22 | for th in lstth: 23 | th.start() 24 | -------------------------------------------------------------------------------- /python/demo12b01_data_race_single.py: -------------------------------------------------------------------------------- 1 | ''' 2 | DATA RACES 3 | Version 01: Without multithreading 4 | ''' 5 | 6 | 7 | 8 | def get_result(n: int): 9 | a = [False] * (n + 1) 10 | 11 | for i in range(1, n + 1): 12 | if i % 2 == 0 or i % 3 == 0: 13 | a[i] = True 14 | 15 | res = a.count(True) 16 | return res 17 | 18 | 19 | 20 | N = 8 21 | result = get_result(N) 22 | print('Number of integers that are divisible by 2 or 3 is:', result) 23 | -------------------------------------------------------------------------------- /python/demo12b02_data_race_multi.py: -------------------------------------------------------------------------------- 1 | ''' 2 | DATA RACES 3 | Version 02: Multithreading 4 | ''' 5 | 6 | import threading 7 | 8 | 9 | 10 | def count_div_2(a: list, n: int): 11 | for i in range(2, n + 1, 2): 12 | a[i] = True 13 | 14 | 15 | 16 | def count_div_3(a: list, n: int): 17 | for i in range(3, n + 1, 3): 18 | a[i] = True 19 | 20 | 21 | 22 | N = 8 23 | A = [False] * (N + 1) 24 | 25 | th_div_2 = threading.Thread(target=count_div_2, args=(A, N)) 26 | th_div_3 = threading.Thread(target=count_div_3, args=(A, N)) 27 | 28 | th_div_2.start() 29 | th_div_3.start() 30 | th_div_2.join() 31 | th_div_3.join() 32 | 33 | result = A.count(True) 34 | 35 | print('Number of integers that are divisible by 2 or 3 is:', result) 36 | -------------------------------------------------------------------------------- /python/demo12c01_race_cond_data_race.py: -------------------------------------------------------------------------------- 1 | ''' 2 | RACE CONDITIONS AND DATA RACES 3 | ''' 4 | 5 | import time 6 | import threading 7 | 8 | 9 | 10 | counter = 0 11 | 12 | 13 | 14 | def do_task(): 15 | global counter 16 | 17 | for _ in range(1000): 18 | temp = counter + 1 19 | time.sleep(0.0001) 20 | counter = temp 21 | 22 | 23 | 24 | lstth = [threading.Thread(target=do_task) for _ in range(32)] 25 | 26 | for th in lstth: 27 | th.start() 28 | 29 | for th in lstth: 30 | th.join() 31 | 32 | print('counter =', counter) 33 | # We are NOT sure that counter = 32000 34 | -------------------------------------------------------------------------------- /python/demo12c02_race_cond_data_race.py: -------------------------------------------------------------------------------- 1 | ''' 2 | RACE CONDITIONS AND DATA RACES 3 | ''' 4 | 5 | import time 6 | import threading 7 | 8 | 9 | 10 | counter = 0 11 | 12 | 13 | 14 | def do_task_a(): 15 | global counter 16 | time.sleep(1) 17 | 18 | while counter < 10: 19 | counter += 1 20 | 21 | print('A won !!!') 22 | 23 | 24 | 25 | def do_task_b(): 26 | global counter 27 | time.sleep(1) 28 | 29 | while counter > -10: 30 | counter -= 1 31 | 32 | print('B won !!!') 33 | 34 | 35 | 36 | threading.Thread(target=do_task_a).start() 37 | threading.Thread(target=do_task_b).start() 38 | -------------------------------------------------------------------------------- /python/demo13a_mutex.py: -------------------------------------------------------------------------------- 1 | ''' 2 | MUTEXES 3 | In Python, Lock objects can be used as mutexes 4 | ''' 5 | 6 | import time 7 | import threading 8 | 9 | 10 | 11 | mutex = threading.Lock() 12 | counter = 0 13 | 14 | 15 | 16 | def do_task(): 17 | global counter 18 | 19 | mutex.acquire() 20 | 21 | for _ in range(1000): 22 | temp = counter + 1 23 | time.sleep(0.0001) 24 | counter = temp 25 | 26 | mutex.release() 27 | 28 | 29 | 30 | NUM_THREADS = 32 31 | lstth = [threading.Thread(target=do_task) for _ in range(NUM_THREADS)] 32 | 33 | for th in lstth: 34 | th.start() 35 | 36 | for th in lstth: 37 | th.join() 38 | 39 | print('counter =', counter) 40 | # We are sure that counter = 32000 41 | -------------------------------------------------------------------------------- /python/demo14_synchronized_block.py: -------------------------------------------------------------------------------- 1 | ''' 2 | SYNCHRONIZED BLOCKS 3 | ''' 4 | 5 | import time 6 | import threading 7 | 8 | 9 | 10 | mutex = threading.Lock() 11 | counter = 0 12 | 13 | 14 | 15 | def do_task(): 16 | global counter 17 | 18 | with mutex: 19 | for _ in range(1000): 20 | temp = counter + 1 21 | time.sleep(0.0001) 22 | counter = temp 23 | 24 | 25 | 26 | NUM_THREADS = 32 27 | lstth = [threading.Thread(target=do_task) for _ in range(NUM_THREADS)] 28 | 29 | for th in lstth: 30 | th.start() 31 | 32 | for th in lstth: 33 | th.join() 34 | 35 | print('counter =', counter) 36 | # We are sure that counter = 32000 37 | -------------------------------------------------------------------------------- /python/demo15a_deadlock.py: -------------------------------------------------------------------------------- 1 | ''' 2 | DEADLOCK 3 | Version A 4 | ''' 5 | 6 | import threading 7 | 8 | 9 | 10 | mutex = threading.Lock() 11 | 12 | 13 | 14 | def do_task(name: str): 15 | mutex.acquire() 16 | print(f'{name} acquired resource') 17 | # mutex.release() # Forget this statement ==> deadlock 18 | 19 | 20 | 21 | th_foo = threading.Thread(target=do_task, args=('foo',)) 22 | th_bar = threading.Thread(target=do_task, args=('bar',)) 23 | 24 | th_foo.start() 25 | th_bar.start() 26 | th_foo.join() 27 | th_bar.join() 28 | 29 | print('You will never see this statement due to deadlock!') 30 | -------------------------------------------------------------------------------- /python/demo15b_deadlock.py: -------------------------------------------------------------------------------- 1 | ''' 2 | DEADLOCK 3 | Version B 4 | ''' 5 | 6 | import time 7 | import threading 8 | 9 | 10 | 11 | mutex_a = threading.Lock() 12 | mutex_b = threading.Lock() 13 | 14 | 15 | 16 | def foo(): 17 | with mutex_a: 18 | print('foo acquired resource A') 19 | time.sleep(1) 20 | with mutex_b: 21 | print('foo acquired resource B') 22 | 23 | 24 | 25 | def bar(): 26 | with mutex_b: 27 | print('bar acquired resource B') 28 | time.sleep(1) 29 | with mutex_a: 30 | print('bar acquired resource A') 31 | 32 | 33 | 34 | th_foo = threading.Thread(target=foo) 35 | th_bar = threading.Thread(target=bar) 36 | 37 | th_foo.start() 38 | th_bar.start() 39 | th_foo.join() 40 | th_bar.join() 41 | 42 | print('You will never see this statement due to deadlock!') 43 | -------------------------------------------------------------------------------- /python/demo16_monitor.py: -------------------------------------------------------------------------------- 1 | ''' 2 | MONITORS 3 | Implementation of a monitor for managing a counter 4 | ''' 5 | 6 | import time 7 | import threading 8 | 9 | 10 | 11 | class Monitor: 12 | def __init__(self, res: dict, field_name: str): 13 | self.__lock = threading.Lock() 14 | self.__res = res 15 | self.__field_name = field_name 16 | 17 | def increase_counter(self): 18 | with self.__lock: 19 | tmp = self.__res[self.__field_name] + 1 20 | time.sleep(0.0001) 21 | self.__res[self.__field_name] = tmp 22 | 23 | 24 | 25 | def do_task(mon: Monitor): 26 | for _ in range(1000): 27 | mon.increase_counter() 28 | 29 | 30 | 31 | result = { 'data': 0 } 32 | monitor = Monitor(result, 'data') 33 | 34 | NUM_THREADS = 32 35 | lstth = [threading.Thread(target=do_task, args=(monitor,)) for _ in range(NUM_THREADS)] 36 | 37 | for th in lstth: 38 | th.start() 39 | 40 | for th in lstth: 41 | th.join() 42 | 43 | print('counter =', result['data']) 44 | # We are sure that counter = 32000 45 | -------------------------------------------------------------------------------- /python/demo17a_reentrant_lock.py: -------------------------------------------------------------------------------- 1 | ''' 2 | REENTRANT LOCKS (RECURSIVE MUTEXES) 3 | Version A: Introduction to reentrant locks 4 | ''' 5 | 6 | import threading 7 | 8 | 9 | 10 | lock = threading.Lock() 11 | 12 | 13 | 14 | def do_task(): 15 | with lock: 16 | print('First time acquiring the resource') 17 | with lock: 18 | print('Second time acquiring the resource') 19 | 20 | 21 | 22 | th = threading.Thread(target=do_task) 23 | th.start() 24 | 25 | # The thread th shall meet deadlock. 26 | # So, you will never get output "Second time the acquiring resource". 27 | -------------------------------------------------------------------------------- /python/demo17b_reentrant_lock.py: -------------------------------------------------------------------------------- 1 | ''' 2 | REENTRANT LOCKS (RECURSIVE MUTEXES) 3 | Version B: Solving the problem from version A 4 | ''' 5 | 6 | import threading 7 | 8 | 9 | 10 | lock = threading.RLock() 11 | 12 | 13 | 14 | def do_task(): 15 | with lock: 16 | print('First time acquiring the resource') 17 | with lock: 18 | print('Second time acquiring the resource') 19 | 20 | 21 | 22 | th = threading.Thread(target=do_task) 23 | th.start() 24 | th.join() 25 | -------------------------------------------------------------------------------- /python/demo17c_reentrant_lock.py: -------------------------------------------------------------------------------- 1 | ''' 2 | REENTRANT LOCKS (RECURSIVE MUTEXES) 3 | Version C: A multithreaded app example 4 | ''' 5 | 6 | import time 7 | import threading 8 | 9 | 10 | 11 | lock = threading.RLock() 12 | 13 | 14 | 15 | def do_task(name: str): 16 | time.sleep(1) 17 | with lock: 18 | print(f'First time {name} acquiring the resource') 19 | with lock: 20 | print(f'Second time {name} acquiring the resource') 21 | 22 | 23 | 24 | NUM_THREADS = 3 25 | 26 | for i in range(NUM_THREADS): 27 | threading.Thread(target=do_task, args=(chr(i + 65),)).start() 28 | -------------------------------------------------------------------------------- /python/demo18a01_barrier.py: -------------------------------------------------------------------------------- 1 | ''' 2 | BARRIERS AND LATCHES 3 | Version A: Barriers 4 | ''' 5 | 6 | import time 7 | import threading 8 | 9 | 10 | 11 | sync_point = threading.Barrier(parties=3) 12 | 13 | 14 | 15 | def process_request(user_name: str, wait_time: int): 16 | time.sleep(wait_time) 17 | 18 | print(f'Get request from {user_name}') 19 | sync_point.wait() 20 | 21 | print(f'Process request for {user_name}') 22 | sync_point.wait() 23 | 24 | print(f'Done {user_name}') 25 | 26 | 27 | 28 | lstarg = [ 29 | ('lorem', 1), 30 | ('ipsum', 2), 31 | ('dolor', 3) 32 | ] 33 | 34 | _ = [ threading.Thread(target=process_request, args=arg).start() for arg in lstarg ] 35 | -------------------------------------------------------------------------------- /python/demo18a02_barrier.py: -------------------------------------------------------------------------------- 1 | ''' 2 | BARRIERS AND LATCHES 3 | Version A: Barriers 4 | ''' 5 | 6 | import time 7 | import threading 8 | 9 | 10 | 11 | sync_point = threading.Barrier(parties=2) 12 | 13 | 14 | 15 | def process_request(user_name: str, wait_time: int): 16 | time.sleep(wait_time) 17 | 18 | print(f'Get request from {user_name}') 19 | sync_point.wait() 20 | 21 | print(f'Process request for {user_name}') 22 | sync_point.wait() 23 | 24 | print(f'Done {user_name}') 25 | 26 | 27 | 28 | lstarg = [ 29 | ('lorem', 1), 30 | ('ipsum', 3), 31 | ('dolor', 3), 32 | ('amet', 10) 33 | ] 34 | 35 | _ = [ threading.Thread(target=process_request, args=arg) for arg in lstarg ] 36 | 37 | # Thread with user_name = "amet" shall be FREEZED 38 | -------------------------------------------------------------------------------- /python/demo18a03_barrier.py: -------------------------------------------------------------------------------- 1 | ''' 2 | BARRIERS AND LATCHES 3 | Version A: Barriers 4 | ''' 5 | 6 | import time 7 | import threading 8 | 9 | 10 | 11 | sync_point_a = threading.Barrier(parties=2) 12 | sync_point_b = threading.Barrier(parties=2) 13 | 14 | 15 | 16 | def process_request(user_name: str, wait_time: int): 17 | time.sleep(wait_time) 18 | 19 | print(f'Get request from {user_name}') 20 | sync_point_a.wait() 21 | 22 | print(f'Process request for {user_name}') 23 | sync_point_b.wait() 24 | 25 | print(f'Done {user_name}') 26 | 27 | 28 | 29 | lstarg = [ 30 | ('lorem', 1), 31 | ('ipsum', 3), 32 | ('dolor', 3), 33 | ('amet', 10) 34 | ] 35 | 36 | _ = [ threading.Thread(target=process_request, args=arg) for arg in lstarg ] 37 | -------------------------------------------------------------------------------- /python/demo18b01_latch.py: -------------------------------------------------------------------------------- 1 | ''' 2 | BARRIERS AND LATCHES 3 | Version B: Count-down latches 4 | 5 | Count-down latches in Python are not supported by default. 6 | So, I use mylib_latch for this demonstration. 7 | ''' 8 | 9 | import time 10 | import threading 11 | from mylib_latch import CountDownLatch 12 | 13 | 14 | 15 | def process_request(user_name: str, wait_time: int): 16 | time.sleep(wait_time) 17 | 18 | print(f'Get request from {user_name}') 19 | 20 | sync_point.count_down() 21 | sync_point.wait() 22 | 23 | print(f'Done {user_name}') 24 | 25 | 26 | 27 | lstarg = [ 28 | ('lorem', 1), 29 | ('ipsum', 2), 30 | ('dolor', 3) 31 | ] 32 | 33 | sync_point = CountDownLatch(count=3) 34 | 35 | _ = [ threading.Thread(target=process_request, args=arg).start() for arg in lstarg ] 36 | -------------------------------------------------------------------------------- /python/demo18b02_latch.py: -------------------------------------------------------------------------------- 1 | ''' 2 | BARRIERS AND LATCHES 3 | Version B: Count-down latches 4 | 5 | Main thread waits for 3 child threads to get enough data to progress. 6 | 7 | Count-down latches in Python are not supported by default. 8 | So, I use mylib_latch for this demonstration. 9 | ''' 10 | 11 | import time 12 | import threading 13 | from mylib_latch import CountDownLatch 14 | 15 | 16 | 17 | def do_task(message: str, wait_time: int): 18 | time.sleep(wait_time) 19 | 20 | print(message) 21 | sync_point.count_down() 22 | 23 | time.sleep(8) 24 | print('Cleanup') 25 | 26 | 27 | 28 | lstarg = [ 29 | ('Send request to egg.net to get data', 6), 30 | ('Send request to foo.org to get data', 2), 31 | ('Send request to bar.com to get data', 4) 32 | ] 33 | 34 | sync_point = CountDownLatch(count=len(lstarg)) 35 | 36 | _ = [ threading.Thread(target=do_task, args=arg).start() for arg in lstarg ] 37 | 38 | sync_point.wait() 39 | print('\nNow we have enough data to progress to next step\n') 40 | -------------------------------------------------------------------------------- /python/demo20a01_semaphore.py: -------------------------------------------------------------------------------- 1 | ''' 2 | SEMAPHORES 3 | Version A: Paper sheets and packages 4 | ''' 5 | 6 | import time 7 | import threading 8 | 9 | 10 | 11 | sem_package = threading.Semaphore(0) 12 | 13 | 14 | 15 | def make_one_sheet(): 16 | for _ in range(4): 17 | print('Make 1 sheet') 18 | time.sleep(1) 19 | sem_package.release() 20 | 21 | 22 | 23 | def combine_one_package(): 24 | for _ in range(4): 25 | sem_package.acquire() 26 | sem_package.acquire() 27 | print('Combine 2 sheets into 1 package') 28 | 29 | 30 | 31 | threading.Thread(target=make_one_sheet).start() 32 | threading.Thread(target=make_one_sheet).start() 33 | threading.Thread(target=combine_one_package).start() 34 | -------------------------------------------------------------------------------- /python/demo20a02_semaphore.py: -------------------------------------------------------------------------------- 1 | ''' 2 | SEMAPHORES 3 | Version A: Paper sheets and packages 4 | ''' 5 | 6 | import time 7 | import threading 8 | 9 | 10 | 11 | sem_package = threading.Semaphore(0) 12 | sem_sheet = threading.Semaphore(2) 13 | 14 | 15 | 16 | def make_one_sheet(): 17 | for _ in range(4): 18 | sem_sheet.acquire() 19 | print('Make 1 sheet') 20 | sem_package.release() 21 | 22 | 23 | 24 | def combine_one_package(): 25 | for _ in range(4): 26 | sem_package.acquire() 27 | sem_package.acquire() 28 | print('Combine 2 sheets into 1 package') 29 | time.sleep(2) 30 | sem_sheet.release() 31 | sem_sheet.release() 32 | 33 | 34 | 35 | threading.Thread(target=make_one_sheet).start() 36 | threading.Thread(target=make_one_sheet).start() 37 | threading.Thread(target=combine_one_package).start() 38 | -------------------------------------------------------------------------------- /python/demo20a03_semaphore_deadlock.py: -------------------------------------------------------------------------------- 1 | ''' 2 | SEMAPHORES 3 | Version A: Paper sheets and packages 4 | ''' 5 | 6 | import time 7 | import threading 8 | 9 | 10 | 11 | sem_package = threading.Semaphore(0) 12 | sem_sheet = threading.Semaphore(2) 13 | 14 | 15 | 16 | def make_one_sheet(): 17 | for _ in range(4): 18 | sem_sheet.acquire() 19 | print('Make 1 sheet') 20 | sem_package.release() 21 | 22 | 23 | 24 | def combine_one_package(): 25 | for _ in range(4): 26 | sem_package.acquire() 27 | sem_package.acquire() 28 | print('Combine 2 sheets into 1 package') 29 | time.sleep(2) 30 | sem_sheet.release() 31 | # sem_sheet.release() # Missing one statement: sem_sheet.release() ==> deadlock 32 | 33 | 34 | 35 | threading.Thread(target=make_one_sheet).start() 36 | threading.Thread(target=make_one_sheet).start() 37 | threading.Thread(target=combine_one_package).start() 38 | -------------------------------------------------------------------------------- /python/demo20b_semaphore.py: -------------------------------------------------------------------------------- 1 | ''' 2 | SEMAPHORES 3 | Version B: Tires and chassis 4 | ''' 5 | 6 | import time 7 | import threading 8 | 9 | 10 | 11 | sem_tire = threading.Semaphore(4) 12 | sem_chassis = threading.Semaphore(0) 13 | 14 | 15 | 16 | def make_tire(): 17 | for _ in range(8): 18 | sem_tire.acquire() 19 | 20 | print('Make 1 tire') 21 | time.sleep(1) 22 | 23 | sem_chassis.release() 24 | 25 | 26 | 27 | def make_chassis(): 28 | for _ in range(4): 29 | sem_chassis.acquire() 30 | sem_chassis.acquire() 31 | sem_chassis.acquire() 32 | sem_chassis.acquire() 33 | 34 | print('Make 1 chassis') 35 | time.sleep(3) 36 | 37 | sem_tire.release() 38 | sem_tire.release() 39 | sem_tire.release() 40 | sem_tire.release() 41 | 42 | 43 | 44 | threading.Thread(target=make_tire).start() 45 | threading.Thread(target=make_tire).start() 46 | threading.Thread(target=make_chassis).start() 47 | -------------------------------------------------------------------------------- /python/demo21a01_condition_variable.py: -------------------------------------------------------------------------------- 1 | ''' 2 | CONDITION VARIABLES 3 | ''' 4 | 5 | import time 6 | import threading 7 | 8 | 9 | 10 | condition_var = threading.Condition() 11 | 12 | 13 | 14 | def foo(): 15 | print('foo is waiting...') 16 | with condition_var: 17 | condition_var.wait() 18 | print('foo resumed') 19 | 20 | 21 | 22 | def bar(): 23 | time.sleep(3) 24 | with condition_var: 25 | condition_var.notify() 26 | 27 | 28 | 29 | threading.Thread(target=foo).start() 30 | threading.Thread(target=bar).start() 31 | -------------------------------------------------------------------------------- /python/demo21a02_condition_variable.py: -------------------------------------------------------------------------------- 1 | ''' 2 | CONDITION VARIABLES 3 | ''' 4 | 5 | import time 6 | import threading 7 | 8 | 9 | 10 | condition_var = threading.Condition() 11 | 12 | 13 | 14 | def foo(): 15 | print('foo is waiting...') 16 | with condition_var: 17 | condition_var.wait() 18 | print('foo resumed') 19 | 20 | 21 | 22 | def bar(): 23 | for _ in range(3): 24 | time.sleep(2) 25 | with condition_var: 26 | condition_var.notify() 27 | 28 | 29 | 30 | _ = [ threading.Thread(target=foo).start() for _ in range(3) ] 31 | threading.Thread(target=bar).start() 32 | -------------------------------------------------------------------------------- /python/demo21a03_condition_variable.py: -------------------------------------------------------------------------------- 1 | ''' 2 | CONDITION VARIABLES 3 | ''' 4 | 5 | import time 6 | import threading 7 | 8 | 9 | 10 | condition_var = threading.Condition() 11 | 12 | 13 | 14 | def foo(): 15 | print('foo is waiting...') 16 | with condition_var: 17 | condition_var.wait() 18 | print('foo resumed') 19 | 20 | 21 | 22 | def bar(): 23 | time.sleep(3) 24 | with condition_var: 25 | # Notify all waiting threads 26 | condition_var.notify_all() 27 | 28 | 29 | 30 | _ = [ threading.Thread(target=foo).start() for _ in range(3) ] 31 | threading.Thread(target=bar).start() 32 | -------------------------------------------------------------------------------- /python/demo22a_blocking_queue.py: -------------------------------------------------------------------------------- 1 | ''' 2 | BLOCKING QUEUES 3 | Version A: A slow producer and a fast consumer 4 | ''' 5 | 6 | import time 7 | from queue import Queue 8 | import threading 9 | 10 | 11 | 12 | def producer(q: Queue): 13 | time.sleep(2) 14 | q.put('Alice') 15 | 16 | time.sleep(2) 17 | q.put('likes') 18 | 19 | time.sleep(2) 20 | q.put('singing') 21 | 22 | 23 | 24 | def consumer(q: Queue): 25 | for _ in range(3): 26 | print('\nWaiting for data...') 27 | data = q.get() 28 | print(f' {data}') 29 | 30 | 31 | 32 | blkq = Queue() 33 | 34 | threading.Thread(target=producer, args=(blkq,)).start() 35 | threading.Thread(target=consumer, args=(blkq,)).start() 36 | -------------------------------------------------------------------------------- /python/demo22b_blocking_queue.py: -------------------------------------------------------------------------------- 1 | ''' 2 | BLOCKING QUEUES 3 | Version B: A fast producer and a slow consumer 4 | ''' 5 | 6 | import time 7 | from queue import Queue 8 | import threading 9 | 10 | 11 | 12 | def producer(q: Queue): 13 | q.put('Alice') 14 | q.put('likes') 15 | 16 | # Due to reaching the maximum capacity = 2, when executing q.put('singing'), 17 | # this thread is going to sleep until the queue removes an element. 18 | q.put('singing') 19 | 20 | 21 | 22 | def consumer(q: Queue): 23 | time.sleep(2) 24 | 25 | for _ in range(3): 26 | print('\nWaiting for data...') 27 | data = q.get() 28 | print(f' {data}') 29 | 30 | 31 | 32 | blkq = Queue(maxsize=2) # blocking queue with capacity = 2 33 | 34 | threading.Thread(target=producer, args=(blkq,)).start() 35 | threading.Thread(target=consumer, args=(blkq,)).start() 36 | -------------------------------------------------------------------------------- /python/demo23a_thread_local.py: -------------------------------------------------------------------------------- 1 | ''' 2 | THREAD-LOCAL STORAGE 3 | ''' 4 | 5 | import time 6 | import threading 7 | 8 | 9 | 10 | data = threading.local() 11 | 12 | 13 | 14 | def print_local_value(): 15 | print(data.value) 16 | 17 | 18 | 19 | def do_task_apple(): 20 | data.value = 'APPLE' 21 | time.sleep(2) 22 | print_local_value() 23 | 24 | 25 | 26 | def do_task_banana(): 27 | data.value = 'BANANA' 28 | time.sleep(2) 29 | print_local_value() 30 | 31 | 32 | 33 | threading.Thread(target=do_task_apple).start() 34 | threading.Thread(target=do_task_banana).start() 35 | -------------------------------------------------------------------------------- /python/demo23b_thread_local.py: -------------------------------------------------------------------------------- 1 | ''' 2 | THREAD-LOCAL STORAGE 3 | Avoiding synchronization using thread-local storage 4 | ''' 5 | 6 | import time 7 | import threading 8 | 9 | 10 | 11 | data = threading.local() 12 | 13 | 14 | 15 | def do_task(t: int): 16 | time.sleep(1) 17 | data.counter = 0 18 | 19 | for _ in range(1000): 20 | data.counter += 1 21 | 22 | print(f'Thread {t} gives counter = {data.counter}') 23 | 24 | 25 | 26 | NUM_THREADS = 3 27 | 28 | for i in range(NUM_THREADS): 29 | threading.Thread(target=do_task, args=(i,)).start() 30 | 31 | # By using thread-local storage, each thread has its own counter. 32 | # So, the counter in one thread is completely independent of each other. 33 | # Thread-local storage helps us to AVOID SYNCHRONIZATION. 34 | -------------------------------------------------------------------------------- /python/demo24_volatile.py: -------------------------------------------------------------------------------- 1 | ''' 2 | THE VOLATILE KEYWORD 3 | The "volatile" keyword in Python are not supported by default. 4 | ''' 5 | -------------------------------------------------------------------------------- /python/demo25_atomic.py: -------------------------------------------------------------------------------- 1 | ''' 2 | ATOMIC ACCESS 3 | The atomic operation syntax in Python is not supported by default. 4 | ''' 5 | -------------------------------------------------------------------------------- /python/demoex_event.py: -------------------------------------------------------------------------------- 1 | ''' 2 | EVENT OBJECTS 3 | ''' 4 | 5 | import time 6 | import threading 7 | 8 | 9 | 10 | # Event to notify the speakers 11 | ev = threading.Event() 12 | running = True 13 | 14 | 15 | 16 | def func_speaker(name: str): 17 | while True: 18 | ev.wait() 19 | 20 | if not running: 21 | return 22 | 23 | print(f'{name}: ring ring ring') 24 | 25 | 26 | 27 | def func_clock(): 28 | global running 29 | 30 | for i in range(89, -1, -1): 31 | minute = i // 60 32 | second = i % 60 33 | print(f'{minute:02d}:{second:02d}') 34 | 35 | if i % 30 == 0: 36 | ev.set() # let speakers do speak 'ring ring ring' 37 | ev.clear() # reset internal flag to reuse the event in the future 38 | 39 | time.sleep(0.2) 40 | 41 | running = False 42 | ev.set() 43 | 44 | 45 | 46 | threading.Thread(target=func_speaker, args=('ham',)).start() 47 | threading.Thread(target=func_speaker, args=('egg',)).start() 48 | threading.Thread(target=func_clock).start() 49 | -------------------------------------------------------------------------------- /python/demoex_timer.py: -------------------------------------------------------------------------------- 1 | ''' 2 | TIMER OBJECTS 3 | ''' 4 | 5 | import time 6 | import threading 7 | 8 | 9 | 10 | def func_time_out(): 11 | print('Time out!!!') 12 | 13 | 14 | 15 | threading.Timer(10, func_time_out).start() 16 | 17 | for i in range(9, -1, -1): 18 | print(i) 19 | time.sleep(1) 20 | -------------------------------------------------------------------------------- /python/exer01a_max_div.py: -------------------------------------------------------------------------------- 1 | ''' 2 | MAXIMUM NUMBER OF DIVISORS 3 | ''' 4 | 5 | import time 6 | 7 | 8 | 9 | RANGE_START = 1 10 | RANGE_END = 30000 11 | 12 | res_value = 0 13 | res_numdiv = 0 # number of divisors of result 14 | 15 | tp_start = time.time() 16 | 17 | 18 | for i in range(RANGE_START, RANGE_END + 1): 19 | numdiv = 0 20 | 21 | for j in range(1, i // 2): 22 | if i % j == 0: 23 | numdiv += 1 24 | 25 | if res_numdiv < numdiv: 26 | res_numdiv = numdiv 27 | res_value = i 28 | 29 | 30 | time_elapsed = time.time() - tp_start 31 | 32 | print('The integer which has largest number of divisors is', res_value) 33 | print('The largest number of divisor is', res_numdiv) 34 | print('Time elapsed =', time_elapsed) 35 | -------------------------------------------------------------------------------- /python/exer02a01_producer_consumer.py: -------------------------------------------------------------------------------- 1 | ''' 2 | THE PRODUCER-CONSUMER PROBLEM 3 | 4 | SOLUTION TYPE A: USING BLOCKING QUEUES 5 | Version A01: 1 slow producer, 1 fast consumer 6 | ''' 7 | 8 | import time 9 | from queue import Queue 10 | import threading 11 | 12 | 13 | 14 | def producer(q: Queue): 15 | i = 1 16 | 17 | while True: 18 | q.put(i) 19 | time.sleep(1) 20 | i += 1 21 | 22 | 23 | 24 | def consumer(q: Queue): 25 | while True: 26 | data = q.get() 27 | print('Consumer', data) 28 | 29 | 30 | 31 | blkq = Queue() 32 | threading.Thread(target=producer, args=(blkq,)).start() 33 | threading.Thread(target=consumer, args=(blkq,)).start() 34 | -------------------------------------------------------------------------------- /python/exer02a02_producer_consumer.py: -------------------------------------------------------------------------------- 1 | ''' 2 | THE PRODUCER-CONSUMER PROBLEM 3 | 4 | SOLUTION TYPE A: USING BLOCKING QUEUES 5 | Version A02: 2 slow producers, 1 fast consumer 6 | ''' 7 | 8 | import time 9 | from queue import Queue 10 | import threading 11 | 12 | 13 | 14 | def producer(q: Queue): 15 | i = 1 16 | 17 | while True: 18 | q.put(i) 19 | time.sleep(1) 20 | i += 1 21 | 22 | 23 | 24 | def consumer(q: Queue): 25 | while True: 26 | data = q.get() 27 | print('Consumer', data) 28 | 29 | 30 | 31 | blkq = Queue() 32 | 33 | threading.Thread(target=producer, args=(blkq,)).start() 34 | threading.Thread(target=producer, args=(blkq,)).start() 35 | 36 | threading.Thread(target=consumer, args=(blkq,)).start() 37 | -------------------------------------------------------------------------------- /python/exer02a03_producer_consumer.py: -------------------------------------------------------------------------------- 1 | ''' 2 | THE PRODUCER-CONSUMER PROBLEM 3 | 4 | SOLUTION TYPE A: USING BLOCKING QUEUES 5 | Version A03: 1 slow producer, 2 fast consumers 6 | ''' 7 | 8 | import time 9 | from queue import Queue 10 | import threading 11 | 12 | 13 | 14 | def producer(q: Queue): 15 | i = 1 16 | 17 | while True: 18 | q.put(i) 19 | time.sleep(1) 20 | i += 1 21 | 22 | 23 | 24 | def consumer(name: str, q: Queue): 25 | while True: 26 | data = q.get() 27 | print(f'Consumer {name}: {data}') 28 | 29 | 30 | 31 | blkq = Queue() 32 | 33 | threading.Thread(target=producer, args=(blkq,)).start() 34 | 35 | threading.Thread(target=consumer, args=('foo', blkq)).start() 36 | threading.Thread(target=consumer, args=('bar', blkq)).start() 37 | -------------------------------------------------------------------------------- /python/exer02a04_producer_consumer.py: -------------------------------------------------------------------------------- 1 | ''' 2 | THE PRODUCER-CONSUMER PROBLEM 3 | 4 | SOLUTION TYPE A: USING BLOCKING QUEUES 5 | Version A04: Multiple fast producers, multiple slow consumers 6 | ''' 7 | 8 | import time 9 | from queue import Queue 10 | import threading 11 | 12 | 13 | 14 | def producer(q: Queue, start_value: int): 15 | time.sleep(1) 16 | i = 1 17 | 18 | while True: 19 | q.put(i + start_value) 20 | i += 1 21 | 22 | 23 | 24 | def consumer(q: Queue): 25 | while True: 26 | data = q.get() 27 | print('Consumer', data) 28 | time.sleep(1) 29 | 30 | 31 | 32 | blkq = Queue(maxsize=5) 33 | NUM_PRODUCERS = 3 34 | NUM_CONSUMERS = 2 35 | 36 | for i in range(NUM_PRODUCERS): 37 | threading.Thread(target=producer, args=(blkq, i * 1000)).start() 38 | 39 | for _ in range(NUM_CONSUMERS): 40 | threading.Thread(target=consumer, args=(blkq,)).start() 41 | -------------------------------------------------------------------------------- /python/exer04_dining_philosophers.py: -------------------------------------------------------------------------------- 1 | ''' 2 | THE DINING PHILOSOPHERS PROBLEM 3 | ''' 4 | 5 | import time 6 | import threading 7 | 8 | 9 | 10 | def do_task_philosopher(chstk: list, n_philo: int, id_philo: int): 11 | time.sleep(1) 12 | 13 | with chstk[id_philo]: 14 | with chstk[(id_philo + 1) % n_philo]: 15 | print(f'Philosopher #{id_philo} is eating the rice') 16 | 17 | 18 | 19 | NUM_PHILOSOPHERS = 5 20 | chopstick = [threading.Lock() for _ in range(NUM_PHILOSOPHERS)] 21 | 22 | for i in range(NUM_PHILOSOPHERS): 23 | threading.Thread(target=do_task_philosopher, args=(chopstick, NUM_PHILOSOPHERS, i)).start() 24 | -------------------------------------------------------------------------------- /python/exer08_exec_service_itask.py: -------------------------------------------------------------------------------- 1 | from abc import ABC, abstractmethod 2 | 3 | 4 | class ITask(ABC): 5 | @abstractmethod 6 | def run(self): 7 | pass 8 | --------------------------------------------------------------------------------