├── .gitattributes ├── .gitignore ├── Chapter01 ├── Makefile └── ch01_mt_example.cpp ├── Chapter02 ├── Makefile └── ch01_mt_example.cpp ├── Chapter03 ├── 1 │ ├── Makefile │ └── ch01_mt_example.cpp ├── 2 │ ├── Makefile │ └── ch01_mt_example.cpp ├── 3 │ ├── Makefile │ └── ch01_mt_example.cpp └── 4 │ ├── Makefile │ └── ch01_mt_example.cpp ├── Chapter04 ├── Makefile ├── abstract_request.h ├── dispatcher.cpp ├── dispatcher.h ├── main.cpp ├── request.cpp ├── request.h ├── worker.cpp └── worker.h ├── Chapter05 ├── 1 │ ├── Makefile │ ├── code1 │ └── code1.cpp ├── 2 │ ├── Makefile │ ├── code1 │ ├── code1.cpp │ └── code1.cpp~ ├── 3 │ ├── Makefile │ ├── code1 │ └── code1.cpp ├── 4 │ ├── Makefile │ ├── code1 │ └── code1.cpp ├── 5 │ ├── Makefile │ ├── code1 │ └── code1.cpp ├── 6 │ ├── Makefile │ ├── code1 │ └── code1.cpp ├── 7 │ ├── Makefile │ ├── code1 │ └── code1.cpp ├── 8 │ ├── Makefile │ ├── code1 │ └── code1.cpp └── 9 │ ├── Makefile │ ├── code1 │ └── code1.cpp ├── Chapter06 ├── Makefile ├── abstract_request.h ├── dispatcher.cpp ├── dispatcher.h ├── main.cpp ├── request.cpp ├── request.h ├── worker.cpp └── worker.h ├── Chapter07 ├── Makefile ├── abstract_request.h ├── dispatcher.cpp ├── dispatcher.h ├── main.cpp ├── request.cpp ├── request.h ├── worker.cpp └── worker.h ├── Chapter08 ├── 1 │ ├── Makefile │ ├── code1 │ └── code1.cpp └── 2 │ ├── Makefile │ ├── code1 │ └── code1.cpp ├── Chapter09 └── 1 │ ├── 1 │ ├── Makefile │ ├── mpi_hello_world │ └── mpi_hello_world.c │ └── 2 │ └── hellohybrid.c ├── Chapter10 └── 1 │ └── code1.cpp ├── LICENSE └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | -------------------------------------------------------------------------------- /Chapter01/Makefile: -------------------------------------------------------------------------------- 1 | 2 | GCC := g++ 3 | 4 | OUTPUT := ch01_mt_example 5 | SOURCES := $(wildcard *.cpp) 6 | CCFLAGS := -std=c++11 -pthread 7 | 8 | all: $(OUTPUT) 9 | 10 | $(OUTPUT): 11 | $(GCC) -o $(OUTPUT) $(CCFLAGS) $(SOURCES) 12 | 13 | clean: 14 | rm $(OUTPUT) 15 | 16 | .PHONY: all 17 | -------------------------------------------------------------------------------- /Chapter01/ch01_mt_example.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ch01_mt_example.cpp - main file for the Chapter 01 multithreaded example. 3 | 4 | Revision 0 5 | 6 | Features: 7 | - 8 | 9 | Notes: 10 | - 11 | 12 | 2016/10/30, Maya Posch 13 | */ 14 | 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | using namespace std; 23 | 24 | 25 | // --- Globals 26 | mutex values_mtx; 27 | mutex cout_mtx; 28 | vector values; 29 | 30 | 31 | int randGen(const int& min, const int& max) { 32 | static thread_local mt19937 generator(hash()(this_thread::get_id())); 33 | uniform_int_distribution distribution(min, max); 34 | return distribution(generator); 35 | } 36 | 37 | 38 | void threadFnc(int tid) { 39 | // Calculate the result. 40 | cout_mtx.lock(); 41 | cout << "Starting thread " << tid << ".\n"; 42 | cout_mtx.unlock(); 43 | 44 | values_mtx.lock(); 45 | int val = values[0]; 46 | values_mtx.unlock(); 47 | 48 | int rval = randGen(0, 10); 49 | val += rval; 50 | 51 | cout_mtx.lock(); 52 | cout << "Thread " << tid << " adding " << rval << ". New value: " << val << ".\n"; 53 | cout_mtx.unlock(); 54 | 55 | values_mtx.lock(); 56 | values.push_back(val); 57 | values_mtx.unlock(); 58 | } 59 | 60 | 61 | int main() { 62 | // Set global data in queue. 63 | values.push_back(42); 64 | 65 | // Start the threads, wait for them to finish. 66 | thread tr1(threadFnc, 1); 67 | thread tr2(threadFnc, 2); 68 | thread tr3(threadFnc, 3); 69 | thread tr4(threadFnc, 4); 70 | 71 | tr1.join(); 72 | tr2.join(); 73 | tr3.join(); 74 | tr4.join(); 75 | 76 | // Read the calculated values. 77 | cout << "Input: " << values[0] << ", Result 1: " << values[1] << ", Result 2: " << values[2] << ", Result 3: " << values[3] << ", Result 4: " << values[4] << "\n"; 78 | 79 | 80 | return 1; 81 | } 82 | -------------------------------------------------------------------------------- /Chapter02/Makefile: -------------------------------------------------------------------------------- 1 | 2 | GCC := g++ 3 | 4 | OUTPUT := ch01_mt_example 5 | SOURCES := $(wildcard *.cpp) 6 | CCFLAGS := -std=c++11 -pthread 7 | 8 | all: $(OUTPUT) 9 | 10 | $(OUTPUT): 11 | $(GCC) -o $(OUTPUT) $(CCFLAGS) $(SOURCES) 12 | 13 | clean: 14 | rm $(OUTPUT) 15 | 16 | .PHONY: all 17 | -------------------------------------------------------------------------------- /Chapter02/ch01_mt_example.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ch01_mt_example.cpp - main file for the Chapter 01 multithreaded example. 3 | 4 | Revision 0 5 | 6 | Features: 7 | - 8 | 9 | Notes: 10 | - 11 | 12 | 2016/10/30, Maya Posch 13 | */ 14 | 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | using namespace std; 23 | 24 | 25 | // --- Globals 26 | mutex values_mtx; 27 | mutex cout_mtx; 28 | vector values; 29 | 30 | 31 | int randGen(const int& min, const int& max) { 32 | static thread_local mt19937 generator(hash() (this_thread::get_id())); 33 | uniform_int_distribution distribution(min, max); 34 | return distribution(generator); 35 | } 36 | 37 | 38 | void threadFnc(int tid) { 39 | cout_mtx.lock(); 40 | cout << "Starting thread " << tid << ".\n"; 41 | cout_mtx.unlock(); 42 | 43 | values_mtx.lock(); 44 | int val = values[0]; 45 | values_mtx.unlock(); 46 | 47 | int rval = randGen(0, 10); 48 | val += rval; 49 | 50 | cout_mtx.lock(); 51 | cout << "Thread " << tid << " adding " << rval << ". New value: " << val << ".\n"; 52 | cout_mtx.unlock(); 53 | 54 | values_mtx.lock(); 55 | values.push_back(val); 56 | values_mtx.unlock(); 57 | } 58 | 59 | 60 | int main() { 61 | // Set global data in queue. 62 | values.push_back(42); 63 | 64 | // Start the threads, wait for them to finish. 65 | thread tr1(threadFnc, 1); 66 | thread tr2(threadFnc, 2); 67 | thread tr3(threadFnc, 3); 68 | thread tr4(threadFnc, 4); 69 | 70 | tr1.join(); 71 | tr2.join(); 72 | tr3.join(); 73 | tr4.join(); 74 | 75 | // Read the calculated values. 76 | cout << "Input: " << values[0] << ", Result 1: " << values[1] << ", Result 2: " << values[2] << ", Result 3: " << values[3] << ", Result 4: " << values[4] << "\n"; 77 | 78 | 79 | return 1; 80 | } 81 | -------------------------------------------------------------------------------- /Chapter03/1/Makefile: -------------------------------------------------------------------------------- 1 | 2 | GCC := g++ 3 | 4 | OUTPUT := ch01_mt_example 5 | SOURCES := $(wildcard *.cpp) 6 | CCFLAGS := -std=c++11 -pthread 7 | 8 | all: $(OUTPUT) 9 | 10 | $(OUTPUT): 11 | $(GCC) -o $(OUTPUT) $(CCFLAGS) $(SOURCES) 12 | 13 | clean: 14 | rm $(OUTPUT) 15 | 16 | .PHONY: all 17 | -------------------------------------------------------------------------------- /Chapter03/1/ch01_mt_example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define NUM_THREADS 5 5 | 6 | static pthread_mutex_t func_mutex = PTHREAD_MUTEX_INITIALIZER; 7 | 8 | void func() { 9 | pthread_mutex_lock(&func_mutex); 10 | 11 | // Do something that's not thread-safe. 12 | 13 | pthread_mutex_unlock(&func_mutex); 14 | } 15 | 16 | void* worker(void* arg) { 17 | int value = *((int*) arg); 18 | 19 | // More business logic. 20 | 21 | return 0; 22 | } 23 | 24 | int main(int argc, char** argv) { 25 | pthread_t threads[NUM_THREADS]; 26 | int thread_args[NUM_THREADS]; 27 | int result_code; 28 | 29 | for (unsigned int i = 0; i < NUM_THREADS; ++i) { 30 | thread_args[i] = i; 31 | result_code = pthread_create(&threads[i], 0, worker, (void*) &thread_args[i]); 32 | } 33 | for (int i = 0; i < NUM_THREADS; ++i) { 34 | result_code = pthread_join(threads[i], 0); 35 | } 36 | 37 | exit(0); 38 | } 39 | -------------------------------------------------------------------------------- /Chapter03/2/Makefile: -------------------------------------------------------------------------------- 1 | 2 | GCC := g++ 3 | 4 | OUTPUT := ch01_mt_example 5 | SOURCES := $(wildcard *.cpp) 6 | CCFLAGS := -std=c++11 -pthread 7 | 8 | all: $(OUTPUT) 9 | 10 | $(OUTPUT): 11 | $(GCC) -o $(OUTPUT) $(CCFLAGS) $(SOURCES) 12 | 13 | clean: 14 | rm $(OUTPUT) 15 | 16 | .PHONY: all 17 | -------------------------------------------------------------------------------- /Chapter03/2/ch01_mt_example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define COUNT_TRIGGER 10 6 | #define COUNT_LIMIT 12 7 | 8 | int count = 0; 9 | int thread_ids[3] = {0,1,2}; 10 | pthread_mutex_t count_mutex; 11 | pthread_cond_t count_cv; 12 | 13 | void* add_count(void* t) { 14 | int tid = (long) t; 15 | for (int i = 0; i < COUNT_TRIGGER; ++i) { 16 | pthread_mutex_lock(&count_mutex); 17 | count++; 18 | if (count == COUNT_LIMIT) { 19 | pthread_cond_signal(&count_cv); 20 | } 21 | 22 | pthread_mutex_unlock(&count_mutex); 23 | sleep(1); 24 | } 25 | 26 | pthread_exit(0); 27 | } 28 | void* watch_count(void* t) { 29 | int tid = (int) t; 30 | 31 | pthread_mutex_lock(&count_mutex); 32 | if (count < COUNT_LIMIT) { 33 | pthread_cond_wait(&count_cv, &count_mutex); 34 | } 35 | 36 | pthread_mutex_unlock(&count_mutex); 37 | pthread_exit(0); 38 | } 39 | 40 | int main (int argc, char* argv[]) { 41 | int tid1 = 1, tid2 = 2, tid3 = 3; 42 | pthread_t threads[3]; 43 | pthread_attr_t attr; 44 | 45 | pthread_mutex_init(&count_mutex, 0); 46 | pthread_cond_init (&count_cv, 0); 47 | 48 | pthread_attr_init(&attr); 49 | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 50 | pthread_create(&threads[0], &attr, watch_count, (void *) tid1); 51 | pthread_create(&threads[1], &attr, add_count, (void *) tid2); 52 | pthread_create(&threads[2], &attr, add_count, (void *) tid3); 53 | 54 | for (int i = 0; i < 3; ++i) { 55 | pthread_join(threads[i], 0); 56 | } 57 | 58 | pthread_attr_destroy(&attr); 59 | pthread_mutex_destroy(&count_mutex); 60 | pthread_cond_destroy(&count_cv); 61 | return 0; 62 | } -------------------------------------------------------------------------------- /Chapter03/3/Makefile: -------------------------------------------------------------------------------- 1 | 2 | GCC := g++ 3 | 4 | OUTPUT := ch01_mt_example 5 | SOURCES := $(wildcard *.cpp) 6 | CCFLAGS := -std=c++11 -pthread 7 | 8 | all: $(OUTPUT) 9 | 10 | $(OUTPUT): 11 | $(GCC) -o $(OUTPUT) $(CCFLAGS) $(SOURCES) 12 | 13 | clean: 14 | rm $(OUTPUT) 15 | 16 | .PHONY: all 17 | -------------------------------------------------------------------------------- /Chapter03/3/ch01_mt_example.cpp: -------------------------------------------------------------------------------- 1 | #include "Poco/Thread.h" 2 | #include "Poco/Runnable.h" 3 | #include "Poco/ThreadLocal.h" 4 | #include 5 | 6 | class Counter: public Poco::Runnable { 7 | void run() { 8 | static Poco::ThreadLocal tls; 9 | for (*tls = 0; *tls < 10; ++(*tls)) { 10 | std::cout << *tls << std::endl; 11 | } 12 | } 13 | }; 14 | 15 | int main(int argc, char** argv) { 16 | Counter counter1; 17 | Counter counter2; 18 | Poco::Thread t1; 19 | Poco::Thread t2; 20 | t1.start(counter1); 21 | t2.start(counter2); 22 | t1.join(); 23 | t2.join(); 24 | return 0; 25 | } -------------------------------------------------------------------------------- /Chapter03/4/Makefile: -------------------------------------------------------------------------------- 1 | 2 | GCC := g++ 3 | 4 | OUTPUT := ch01_mt_example 5 | SOURCES := $(wildcard *.cpp) 6 | CCFLAGS := -std=c++11 -pthread 7 | 8 | all: $(OUTPUT) 9 | 10 | $(OUTPUT): 11 | $(GCC) -o $(OUTPUT) $(CCFLAGS) $(SOURCES) 12 | 13 | clean: 14 | rm $(OUTPUT) 15 | 16 | .PHONY: all 17 | -------------------------------------------------------------------------------- /Chapter03/4/ch01_mt_example.cpp: -------------------------------------------------------------------------------- 1 | #include "Poco/ThreadPool.h" 2 | #include "Poco/Runnable.h" 3 | #include 4 | 5 | class HelloRunnable: public Poco::Runnable { 6 | virtual void run() { 7 | std::cout << "Hello, world!" << std::endl; 8 | } 9 | }; 10 | 11 | int main(int argc, char** argv) { 12 | HelloRunnable runnable; 13 | Poco::ThreadPool::defaultPool().start(runnable); 14 | Poco::ThreadPool::defaultPool().joinAll(); 15 | return 0; 16 | } -------------------------------------------------------------------------------- /Chapter04/Makefile: -------------------------------------------------------------------------------- 1 | 2 | GCC := g++ 3 | 4 | OUTPUT := dispatcher_demo 5 | SOURCES := $(wildcard *.cpp) 6 | CCFLAGS := -std=c++11 -g3 7 | 8 | all: $(OUTPUT) 9 | 10 | $(OUTPUT): 11 | $(GCC) -o $(OUTPUT) $(CCFLAGS) $(SOURCES) 12 | 13 | clean: 14 | rm $(OUTPUT) 15 | 16 | .PHONY: all 17 | -------------------------------------------------------------------------------- /Chapter04/abstract_request.h: -------------------------------------------------------------------------------- 1 | /* 2 | abstractrequest.h - header file for the AbstractRequest class. 3 | 4 | Revision 0 5 | 6 | Notes: 7 | - 8 | 9 | 2016/11/19, Maya Posch 10 | (c) Nyanko.ws 11 | */ 12 | 13 | 14 | #pragma once 15 | #ifndef ABSTRACT_REQUEST_H 16 | #define ABSTRACT_REQUEST_H 17 | 18 | 19 | class AbstractRequest { 20 | // 21 | 22 | public: 23 | virtual void setValue(int value) = 0; 24 | virtual void process() = 0; 25 | virtual void finish() = 0; 26 | }; 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /Chapter04/dispatcher.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | dispatcher.cpp - Implementation of the Dispatcher class. 3 | 4 | Revision 0 5 | 6 | Features: 7 | - 8 | 9 | Notes: 10 | - 11 | 12 | 2016/11/19, Maya Posch 13 | (c) Nyanko.ws 14 | */ 15 | 16 | 17 | #include "dispatcher.h" 18 | 19 | #include 20 | using namespace std; 21 | 22 | 23 | // Static initialisations. 24 | queue Dispatcher::requests; 25 | queue Dispatcher::workers; 26 | mutex Dispatcher::requestsMutex; 27 | mutex Dispatcher::workersMutex; 28 | vector Dispatcher::allWorkers; 29 | vector Dispatcher::threads; 30 | 31 | 32 | // --- INIT --- 33 | // Start the number of requested worker threads. 34 | bool Dispatcher::init(int workers) { 35 | thread* t = 0; 36 | Worker* w = 0; 37 | for (int i = 0; i < workers; ++i) { 38 | w = new Worker; 39 | allWorkers.push_back(w); 40 | t = new thread(&Worker::run, w); 41 | threads.push_back(t); 42 | } 43 | 44 | return true; 45 | } 46 | 47 | 48 | // --- STOP --- 49 | // Terminate the worker threads and clean up. 50 | bool Dispatcher::stop() { 51 | for (int i = 0; i < allWorkers.size(); ++i) { 52 | allWorkers[i]->stop(); 53 | } 54 | 55 | cout << "Stopped workers.\n"; 56 | 57 | for (int j = 0; j < threads.size(); ++j) { 58 | threads[j]->join(); 59 | 60 | cout << "Joined threads.\n"; 61 | } 62 | 63 | return true; 64 | } 65 | 66 | 67 | // --- ADD REQUEST --- 68 | void Dispatcher::addRequest(AbstractRequest* request) { 69 | // Check whether there's a worker available in the workers queue, else add 70 | // the request to the requests queue. 71 | workersMutex.lock(); 72 | if (!workers.empty()) { 73 | Worker* worker = workers.front(); 74 | worker->setRequest(request); 75 | condition_variable* cv; 76 | worker->getCondition(cv); 77 | cv->notify_one(); 78 | workers.pop(); 79 | workersMutex.unlock(); 80 | } 81 | else { 82 | workersMutex.unlock(); 83 | requestsMutex.lock(); 84 | requests.push(request); 85 | requestsMutex.unlock(); 86 | } 87 | 88 | 89 | } 90 | 91 | 92 | // --- ADD WORKER --- 93 | bool Dispatcher::addWorker(Worker* worker) { 94 | // If a request is waiting in the requests queue, assign it to the worker. 95 | // Else add the worker to the workers queue. 96 | // Returns true if the worker was added to the queue and has to wait for 97 | // its condition variable. 98 | bool wait = true; 99 | requestsMutex.lock(); 100 | if (!requests.empty()) { 101 | AbstractRequest* request = requests.front(); 102 | worker->setRequest(request); 103 | requests.pop(); 104 | wait = false; 105 | requestsMutex.unlock(); 106 | } 107 | else { 108 | requestsMutex.unlock(); 109 | workersMutex.lock(); 110 | workers.push(worker); 111 | workersMutex.unlock(); 112 | } 113 | 114 | return wait; 115 | } 116 | -------------------------------------------------------------------------------- /Chapter04/dispatcher.h: -------------------------------------------------------------------------------- 1 | /* 2 | dispatcher.h - header file for the Dispatcher class. 3 | 4 | Revision 0 5 | 6 | Notes: 7 | - 8 | 9 | 2016/11/19, Maya Posch 10 | (c) Nyanko.ws. 11 | */ 12 | 13 | 14 | #pragma once 15 | #ifndef DISPATCHER_H 16 | #define DISPATCHER_H 17 | 18 | #include "abstract_request.h" 19 | #include "worker.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | using namespace std; 27 | 28 | 29 | class Dispatcher { 30 | static queue requests; 31 | static queue workers; 32 | static mutex requestsMutex; 33 | static mutex workersMutex; 34 | static vector allWorkers; 35 | static vector threads; 36 | 37 | public: 38 | static bool init(int workers); 39 | static bool stop(); 40 | static void addRequest(AbstractRequest* request); 41 | static bool addWorker(Worker* worker); 42 | }; 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /Chapter04/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | main.cpp - Main file for the Dispatcher demo application. 3 | 4 | Revision 0 5 | 6 | Features: 7 | - 8 | 9 | Notes: 10 | - 11 | 12 | 2016/11/19, Maya Posch 13 | (c) Nyanko.ws 14 | */ 15 | 16 | 17 | #include "dispatcher.h" 18 | #include "request.h" 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | using namespace std; 27 | 28 | 29 | // Globals 30 | sig_atomic_t signal_caught = 0; 31 | mutex logMutex; 32 | 33 | 34 | void sigint_handler(int sig) { 35 | signal_caught = 1; 36 | } 37 | 38 | 39 | void logFnc(string text) { 40 | logMutex.lock(); 41 | cout << text << "\n"; 42 | logMutex.unlock(); 43 | } 44 | 45 | 46 | int main() { 47 | // Install signal handler. 48 | signal(SIGINT, &sigint_handler); 49 | 50 | // Initialise the dispatcher with 10 worker threads. 51 | Dispatcher::init(10); 52 | 53 | cout << "Initialised.\n"; 54 | 55 | // Generate requests in a continuous loop until terminated with SIGINT or 56 | // limit has been reached. 57 | int cycles = 0; 58 | Request* rq = 0; 59 | while (!signal_caught && cycles < 50) { 60 | rq = new Request(); 61 | rq->setValue(cycles); 62 | rq->setOutput(&logFnc); 63 | Dispatcher::addRequest(rq); 64 | cycles++; 65 | } 66 | 67 | this_thread::sleep_for(chrono::seconds(5)); 68 | 69 | // Cleanup. 70 | Dispatcher::stop(); 71 | cout << "Clean-up done.\n"; 72 | 73 | return 0; 74 | } 75 | -------------------------------------------------------------------------------- /Chapter04/request.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | request.cpp - implementation of the Request class. 3 | 4 | Revision 0 5 | 6 | Notes: 7 | - 8 | 9 | 2016/11/19, Maya Posch 10 | (c) Nyanko.ws 11 | */ 12 | 13 | 14 | #include "request.h" 15 | 16 | 17 | // --- PROCESS --- 18 | void Request::process() { 19 | outFnc("Starting processing request " + std::to_string(value) + "..."); 20 | 21 | // 22 | } 23 | 24 | 25 | // --- FINISH --- 26 | void Request::finish() { 27 | outFnc("Finished request " + std::to_string(value)); 28 | } 29 | -------------------------------------------------------------------------------- /Chapter04/request.h: -------------------------------------------------------------------------------- 1 | /* 2 | request.h - header file for the Request class. 3 | 4 | Revision 0 5 | 6 | Notes: 7 | - 8 | 9 | 2016/11/19, Maya Posch 10 | (c) Nyanko.ws 11 | */ 12 | 13 | 14 | #pragma once 15 | #ifndef REQUEST_H 16 | #define REQUEST_H 17 | 18 | #include "abstract_request.h" 19 | 20 | 21 | #include 22 | 23 | using namespace std; 24 | 25 | 26 | typedef void (*logFunction)(string text); 27 | 28 | 29 | class Request : public AbstractRequest { 30 | int value; 31 | logFunction outFnc; 32 | 33 | public: 34 | void setValue(int value) { this->value = value; } 35 | void setOutput(logFunction fnc) { outFnc = fnc; } 36 | void process(); 37 | void finish(); 38 | }; 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /Chapter04/worker.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | worker.cpp - Implementation of the Worker class. 3 | 4 | Revision 0 5 | 6 | Features: 7 | - 8 | 9 | Notes: 10 | - 11 | 12 | 2016/11/19, Maya Posch 13 | (c) Nyanko.ws 14 | */ 15 | 16 | 17 | #include "worker.h" 18 | #include "dispatcher.h" 19 | 20 | #include 21 | 22 | using namespace std; 23 | 24 | 25 | // --- GET CONDITION --- 26 | void Worker::getCondition(condition_variable* &cv) { 27 | cv = &(this)->cv; 28 | } 29 | 30 | 31 | // --- RUN --- 32 | // Runs the worker instance. 33 | void Worker::run() { 34 | while (running) { 35 | if (ready) { 36 | // Execute the request. 37 | ready = false; 38 | request->process(); 39 | request->finish(); 40 | } 41 | 42 | // Add self to Dispatcher queue and execute next request or wait. 43 | if (Dispatcher::addWorker(this)) { 44 | // Use the ready loop to deal with spurious wake-ups. 45 | while (!ready && running) { 46 | if (cv.wait_for(ulock, chrono::seconds(1)) == cv_status::timeout) { 47 | // We timed out, but we keep waiting unless the worker is 48 | // stopped by the dispatcher. 49 | } 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Chapter04/worker.h: -------------------------------------------------------------------------------- 1 | /* 2 | worker.h - Header file for the Worker class. 3 | 4 | Revision 0 5 | 6 | Notes: 7 | - 8 | 9 | 2016/11/19, Maya Posch 10 | (c) Nyanko.ws 11 | */ 12 | 13 | 14 | #pragma once 15 | #ifndef WORKER_H 16 | #define WORKER_H 17 | 18 | #include "abstract_request.h" 19 | 20 | #include 21 | #include 22 | 23 | using namespace std; 24 | 25 | 26 | class Worker { 27 | condition_variable cv; 28 | mutex mtx; 29 | unique_lock ulock; 30 | AbstractRequest* request; 31 | bool running; 32 | bool ready; 33 | 34 | public: 35 | Worker() { running = true; ready = false; ulock = unique_lock(mtx); } 36 | void run(); 37 | void stop() { running = false; } 38 | void setRequest(AbstractRequest* request) { this->request = request; ready = true; } 39 | void getCondition(condition_variable* &cv); 40 | }; 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /Chapter05/1/Makefile: -------------------------------------------------------------------------------- 1 | 2 | GCC := g++ 3 | 4 | OUTPUT := code1 5 | SOURCES := $(wildcard *.cpp) 6 | CCFLAGS := -std=c++11 7 | 8 | all: $(OUTPUT) 9 | 10 | $(OUTPUT): 11 | $(GCC) $(SOURCES) -o $(OUTPUT) -pthread $(CCFLAGS) 12 | 13 | clean: 14 | rm $(OUTPUT) 15 | 16 | .PHONY: all 17 | -------------------------------------------------------------------------------- /Chapter05/1/code1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-CPP-Multithreading/4ee2b49789f1920260f1135908d0a3cf05f20a9d/Chapter05/1/code1 -------------------------------------------------------------------------------- /Chapter05/1/code1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | std::mutex display_mutex; 7 | 8 | void worker() { 9 | std::thread::id this_id = std::this_thread::get_id(); 10 | 11 | display_mutex.lock(); 12 | std::cout << "thread " << this_id << " sleeping...\n"; 13 | display_mutex.unlock(); 14 | 15 | std::this_thread::sleep_for(std::chrono::seconds(1)); 16 | } 17 | 18 | int main() { 19 | std::thread t1(worker); 20 | std::thread::id t1_id = t1.get_id(); 21 | 22 | std::thread t2(worker); 23 | std::thread::id t2_id = t2.get_id(); 24 | 25 | display_mutex.lock(); 26 | std::cout << "t1's id: " << t1_id << "\n"; 27 | std::cout << "t2's id: " << t2_id << "\n"; 28 | display_mutex.unlock(); 29 | 30 | t1.join(); 31 | t2.join(); 32 | 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /Chapter05/2/Makefile: -------------------------------------------------------------------------------- 1 | 2 | GCC := g++ 3 | 4 | OUTPUT := code1 5 | SOURCES := $(wildcard *.cpp) 6 | CCFLAGS := -std=c++11 7 | 8 | all: $(OUTPUT) 9 | 10 | $(OUTPUT): 11 | $(GCC) $(SOURCES) -o $(OUTPUT) -pthread $(CCFLAGS) 12 | 13 | clean: 14 | rm $(OUTPUT) 15 | 16 | .PHONY: all 17 | -------------------------------------------------------------------------------- /Chapter05/2/code1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-CPP-Multithreading/4ee2b49789f1920260f1135908d0a3cf05f20a9d/Chapter05/2/code1 -------------------------------------------------------------------------------- /Chapter05/2/code1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | typedef std::chrono::time_point timepoint; 5 | int main() { 6 | std::cout << "Starting sleep.\n"; 7 | 8 | timepoint start = std::chrono::high_resolution_clock::now(); 9 | 10 | std::this_thread::sleep_for(std::chrono::seconds(2)); 11 | 12 | timepoint end = std::chrono::high_resolution_clock::now(); 13 | std::chrono::duration elapsed = end - start; 14 | std::cout << "Slept for: " << elapsed.count() << " ms\n"; 15 | } 16 | -------------------------------------------------------------------------------- /Chapter05/2/code1.cpp~: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std::chrono_literals; 5 | typedef std::chrono::time_point timepoint; 6 | int main() { 7 | std::cout << "Starting sleep.\n"; 8 | 9 | timepoint start = std::chrono::high_resolution_clock::now(); 10 | 11 | std::this_thread::sleep_for(1); 12 | 13 | timepoint end = std::chrono::high_resolution_clock::now(); 14 | std::chrono::duration elapsed = end - start; 15 | std::cout << "Slept for: " << elapsed.count() << " ms\n"; 16 | } 17 | -------------------------------------------------------------------------------- /Chapter05/3/Makefile: -------------------------------------------------------------------------------- 1 | 2 | GCC := g++ 3 | 4 | OUTPUT := code1 5 | SOURCES := $(wildcard *.cpp) 6 | CCFLAGS := -std=c++11 7 | 8 | all: $(OUTPUT) 9 | 10 | $(OUTPUT): 11 | $(GCC) $(SOURCES) -o $(OUTPUT) -pthread $(CCFLAGS) 12 | 13 | clean: 14 | rm $(OUTPUT) 15 | 16 | .PHONY: all 17 | -------------------------------------------------------------------------------- /Chapter05/3/code1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-CPP-Multithreading/4ee2b49789f1920260f1135908d0a3cf05f20a9d/Chapter05/3/code1 -------------------------------------------------------------------------------- /Chapter05/3/code1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void worker() { 6 | std::this_thread::sleep_for(std::chrono::seconds(1)); 7 | } 8 | 9 | int main() { 10 | std::thread t1(worker); 11 | std::thread t2(worker); 12 | 13 | std::cout << "thread 1 id: " << t1.get_id() << "\n"; 14 | std::cout << "thread 2 id: " << t2.get_id() << "\n"; 15 | 16 | std::swap(t1, t2); 17 | 18 | std::cout << "Swapping threads..." << "\n"; 19 | 20 | std::cout << "thread 1 id: " << t1.get_id() << "\n"; 21 | std::cout << "thread 2 id: " << t2.get_id() << "\n"; 22 | 23 | t1.swap(t2); 24 | 25 | std::cout << "Swapping threads..." << "\n"; 26 | 27 | std::cout << "thread 1 id: " << t1.get_id() << "\n"; 28 | std::cout << "thread 2 id: " << t2.get_id() << "\n"; 29 | 30 | t1.join(); 31 | t2.join(); 32 | } 33 | -------------------------------------------------------------------------------- /Chapter05/4/Makefile: -------------------------------------------------------------------------------- 1 | 2 | GCC := g++ 3 | 4 | OUTPUT := code1 5 | SOURCES := $(wildcard *.cpp) 6 | CCFLAGS := -std=c++11 7 | 8 | all: $(OUTPUT) 9 | 10 | $(OUTPUT): 11 | $(GCC) $(SOURCES) -o $(OUTPUT) -pthread $(CCFLAGS) 12 | 13 | clean: 14 | rm $(OUTPUT) 15 | 16 | .PHONY: all 17 | -------------------------------------------------------------------------------- /Chapter05/4/code1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-CPP-Multithreading/4ee2b49789f1920260f1135908d0a3cf05f20a9d/Chapter05/4/code1 -------------------------------------------------------------------------------- /Chapter05/4/code1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void worker(int i) { 5 | std::cout << "Outputting this from thread number: " << i << "\n"; 6 | } 7 | 8 | int main() { 9 | std::thread t1(worker, 1); 10 | std::thread t2(worker, 2); 11 | 12 | t1.join(); 13 | t2.join(); 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /Chapter05/5/Makefile: -------------------------------------------------------------------------------- 1 | 2 | GCC := g++ 3 | 4 | OUTPUT := code1 5 | SOURCES := $(wildcard *.cpp) 6 | CCFLAGS := -std=c++11 7 | 8 | all: $(OUTPUT) 9 | 10 | $(OUTPUT): 11 | $(GCC) $(SOURCES) -o $(OUTPUT) -pthread $(CCFLAGS) 12 | 13 | clean: 14 | rm $(OUTPUT) 15 | 16 | .PHONY: all 17 | -------------------------------------------------------------------------------- /Chapter05/5/code1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-CPP-Multithreading/4ee2b49789f1920260f1135908d0a3cf05f20a9d/Chapter05/5/code1 -------------------------------------------------------------------------------- /Chapter05/5/code1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | std::mutex globalMutex; 6 | 7 | void worker(int i) { 8 | globalMutex.lock(); 9 | std::cout << "Outputting this from thread number: " << i << "\n"; 10 | globalMutex.unlock(); 11 | } 12 | 13 | int main() { 14 | std::thread t1(worker, 1); 15 | std::thread t2(worker, 2); 16 | 17 | t1.join(); 18 | t2.join(); 19 | 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /Chapter05/6/Makefile: -------------------------------------------------------------------------------- 1 | 2 | GCC := g++ 3 | 4 | OUTPUT := code1 5 | SOURCES := $(wildcard *.cpp) 6 | CCFLAGS := -std=c++11 7 | 8 | all: $(OUTPUT) 9 | 10 | $(OUTPUT): 11 | $(GCC) $(SOURCES) -o $(OUTPUT) -pthread $(CCFLAGS) 12 | 13 | clean: 14 | rm $(OUTPUT) 15 | 16 | .PHONY: all 17 | -------------------------------------------------------------------------------- /Chapter05/6/code1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-CPP-Multithreading/4ee2b49789f1920260f1135908d0a3cf05f20a9d/Chapter05/6/code1 -------------------------------------------------------------------------------- /Chapter05/6/code1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | std::chrono::milliseconds interval(50); 7 | 8 | std::mutex mutex; 9 | int job_shared = 0; 10 | int job_exclusive = 0; 11 | 12 | void worker0() { 13 | std::this_thread::sleep_for(interval); 14 | 15 | while (true) { 16 | if (mutex.try_lock()) { 17 | std::cout << "Shared (" << job_shared << ")\n"; 18 | mutex.unlock(); 19 | return; 20 | } 21 | else { 22 | ++job_exclusive; 23 | std::cout << "Exclusive (" << job_exclusive << ")\n"; 24 | std::this_thread::sleep_for(interval); 25 | } 26 | } 27 | } 28 | 29 | void worker1() { 30 | mutex.lock(); 31 | std::this_thread::sleep_for(10 * interval); 32 | ++job_shared; 33 | mutex.unlock(); 34 | } 35 | 36 | int main() { 37 | std::thread t1(worker0); 38 | std::thread t2(worker1); 39 | 40 | t1.join(); 41 | t2.join(); 42 | } 43 | -------------------------------------------------------------------------------- /Chapter05/7/Makefile: -------------------------------------------------------------------------------- 1 | 2 | GCC := g++ 3 | 4 | OUTPUT := code1 5 | SOURCES := $(wildcard *.cpp) 6 | CCFLAGS := -std=c++11 7 | 8 | all: $(OUTPUT) 9 | 10 | $(OUTPUT): 11 | $(GCC) $(SOURCES) -o $(OUTPUT) -pthread $(CCFLAGS) 12 | 13 | clean: 14 | rm $(OUTPUT) 15 | 16 | .PHONY: all 17 | -------------------------------------------------------------------------------- /Chapter05/7/code1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-CPP-Multithreading/4ee2b49789f1920260f1135908d0a3cf05f20a9d/Chapter05/7/code1 -------------------------------------------------------------------------------- /Chapter05/7/code1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int counter = 0; 6 | std::mutex counter_mutex; 7 | 8 | void worker() { 9 | std::lock_guard lock(counter_mutex); 10 | if (counter == 1) { counter += 10; } 11 | else if (counter >= 10) { counter += 15; } 12 | else if (counter >= 50) { return; } 13 | else { ++counter; } 14 | 15 | std::cout << std::this_thread::get_id() << ": " << counter << '\n'; 16 | } 17 | 18 | int main() { 19 | std::cout << __func__ << ": " << counter << '\n'; 20 | 21 | std::thread t1(worker); 22 | std::thread t2(worker); 23 | 24 | t1.join(); 25 | t2.join(); 26 | 27 | std::cout << __func__ << ": " << counter << '\n'; 28 | } 29 | -------------------------------------------------------------------------------- /Chapter05/8/Makefile: -------------------------------------------------------------------------------- 1 | 2 | GCC := g++ 3 | 4 | OUTPUT := code1 5 | SOURCES := $(wildcard *.cpp) 6 | CCFLAGS := -std=c++11 7 | 8 | all: $(OUTPUT) 9 | 10 | $(OUTPUT): 11 | $(GCC) $(SOURCES) -o $(OUTPUT) -pthread $(CCFLAGS) 12 | 13 | clean: 14 | rm $(OUTPUT) 15 | 16 | .PHONY: all 17 | -------------------------------------------------------------------------------- /Chapter05/8/code1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-CPP-Multithreading/4ee2b49789f1920260f1135908d0a3cf05f20a9d/Chapter05/8/code1 -------------------------------------------------------------------------------- /Chapter05/8/code1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | int countdown (int from, int to) { 9 | for (int i = from; i != to; --i) { 10 | cout << i << '\n'; 11 | this_thread::sleep_for(chrono::seconds(1)); 12 | } 13 | 14 | cout << "Finished countdown.\n"; 15 | return from - to; 16 | } 17 | 18 | int main () { 19 | packaged_task task(countdown); 20 | future result = task.get_future(); 21 | thread t (std::move(task), 10, 0); 22 | 23 | // Other logic. 24 | 25 | int value = result.get(); 26 | 27 | cout << "The countdown lasted for " << value << " seconds.\n"; 28 | 29 | t.join(); 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /Chapter05/9/Makefile: -------------------------------------------------------------------------------- 1 | 2 | GCC := g++ 3 | 4 | OUTPUT := code1 5 | SOURCES := $(wildcard *.cpp) 6 | CCFLAGS := -std=c++11 7 | 8 | all: $(OUTPUT) 9 | 10 | $(OUTPUT): 11 | $(GCC) $(SOURCES) -o $(OUTPUT) -pthread $(CCFLAGS) 12 | 13 | clean: 14 | rm $(OUTPUT) 15 | 16 | .PHONY: all 17 | -------------------------------------------------------------------------------- /Chapter05/9/code1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-CPP-Multithreading/4ee2b49789f1920260f1135908d0a3cf05f20a9d/Chapter05/9/code1 -------------------------------------------------------------------------------- /Chapter05/9/code1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | bool is_prime (int x) { 7 | cout << "Calculating prime...\n"; 8 | for (int i = 2; i < x; ++i) { 9 | if (x % i == 0) { 10 | return false; 11 | } 12 | } 13 | 14 | return true; 15 | } 16 | 17 | int main () { 18 | future pFuture = std::async (is_prime, 343321); 19 | 20 | cout << "Checking whether 343321 is a prime number.\n"; 21 | 22 | // Wait for future object to be ready. 23 | 24 | bool result = pFuture.get(); 25 | if (result) { 26 | cout << "Prime found.\n"; 27 | } 28 | else { 29 | cout << "No prime found.\n"; 30 | } 31 | 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /Chapter06/Makefile: -------------------------------------------------------------------------------- 1 | 2 | GCC := g++ 3 | 4 | OUTPUT := dispatcher_demo 5 | SOURCES := $(wildcard *.cpp) 6 | CCFLAGS := -std=c++11 -g3 7 | 8 | all: $(OUTPUT) 9 | 10 | $(OUTPUT): 11 | $(GCC) -o $(OUTPUT) $(CCFLAGS) $(SOURCES) 12 | 13 | clean: 14 | rm $(OUTPUT) 15 | 16 | .PHONY: all 17 | -------------------------------------------------------------------------------- /Chapter06/abstract_request.h: -------------------------------------------------------------------------------- 1 | /* 2 | abstractrequest.h - header file for the AbstractRequest class. 3 | 4 | Revision 0 5 | 6 | Notes: 7 | - 8 | 9 | 2016/11/19, Maya Posch 10 | (c) Nyanko.ws 11 | */ 12 | 13 | 14 | #pragma once 15 | #ifndef ABSTRACT_REQUEST_H 16 | #define ABSTRACT_REQUEST_H 17 | 18 | 19 | class AbstractRequest { 20 | // 21 | 22 | public: 23 | virtual void setValue(int value) = 0; 24 | virtual void process() = 0; 25 | virtual void finish() = 0; 26 | }; 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /Chapter06/dispatcher.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | dispatcher.cpp - Implementation of the Dispatcher class. 3 | 4 | Revision 0 5 | 6 | Features: 7 | - 8 | 9 | Notes: 10 | - 11 | 12 | 2016/11/19, Maya Posch 13 | (c) Nyanko.ws 14 | */ 15 | 16 | 17 | #include "dispatcher.h" 18 | 19 | #include 20 | using namespace std; 21 | 22 | 23 | // Static initialisations. 24 | queue Dispatcher::requests; 25 | queue Dispatcher::workers; 26 | mutex Dispatcher::requestsMutex; 27 | mutex Dispatcher::workersMutex; 28 | vector Dispatcher::allWorkers; 29 | vector Dispatcher::threads; 30 | 31 | 32 | // --- INIT --- 33 | // Start the number of requested worker threads. 34 | bool Dispatcher::init(int workers) { 35 | thread* t = 0; 36 | Worker* w = 0; 37 | for (int i = 0; i < workers; ++i) { 38 | w = new Worker; 39 | allWorkers.push_back(w); 40 | t = new thread(&Worker::run, w); 41 | threads.push_back(t); 42 | } 43 | 44 | return true; 45 | } 46 | 47 | 48 | // --- STOP --- 49 | // Terminate the worker threads and clean up. 50 | bool Dispatcher::stop() { 51 | for (int i = 0; i < allWorkers.size(); ++i) { 52 | allWorkers[i]->stop(); 53 | } 54 | 55 | cout << "Stopped workers.\n"; 56 | 57 | for (int j = 0; j < threads.size(); ++j) { 58 | threads[j]->join(); 59 | 60 | cout << "Joined threads.\n"; 61 | } 62 | 63 | return true; 64 | } 65 | 66 | 67 | // --- ADD REQUEST --- 68 | void Dispatcher::addRequest(AbstractRequest* request) { 69 | // Check whether there's a worker available in the workers queue, else add 70 | // the request to the requests queue. 71 | workersMutex.lock(); 72 | if (!workers.empty()) { 73 | Worker* worker = workers.front(); 74 | worker->setRequest(request); 75 | condition_variable* cv; 76 | worker->getCondition(cv); 77 | cv->notify_one(); 78 | workers.pop(); 79 | workersMutex.unlock(); 80 | } 81 | else { 82 | workersMutex.unlock(); 83 | requestsMutex.lock(); 84 | requests.push(request); 85 | requestsMutex.unlock(); 86 | } 87 | 88 | 89 | } 90 | 91 | 92 | // --- ADD WORKER --- 93 | bool Dispatcher::addWorker(Worker* worker) { 94 | // If a request is waiting in the requests queue, assign it to the worker. 95 | // Else add the worker to the workers queue. 96 | // Returns true if the worker was added to the queue and has to wait for 97 | // its condition variable. 98 | bool wait = true; 99 | requestsMutex.lock(); 100 | if (!requests.empty()) { 101 | AbstractRequest* request = requests.front(); 102 | worker->setRequest(request); 103 | requests.pop(); 104 | wait = false; 105 | requestsMutex.unlock(); 106 | } 107 | else { 108 | requestsMutex.unlock(); 109 | workersMutex.lock(); 110 | workers.push(worker); 111 | workersMutex.unlock(); 112 | } 113 | 114 | return wait; 115 | } 116 | -------------------------------------------------------------------------------- /Chapter06/dispatcher.h: -------------------------------------------------------------------------------- 1 | /* 2 | dispatcher.h - header file for the Dispatcher class. 3 | 4 | Revision 0 5 | 6 | Notes: 7 | - 8 | 9 | 2016/11/19, Maya Posch 10 | (c) Nyanko.ws. 11 | */ 12 | 13 | 14 | #pragma once 15 | #ifndef DISPATCHER_H 16 | #define DISPATCHER_H 17 | 18 | #include "abstract_request.h" 19 | #include "worker.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | using namespace std; 27 | 28 | 29 | class Dispatcher { 30 | static queue requests; 31 | static queue workers; 32 | static mutex requestsMutex; 33 | static mutex workersMutex; 34 | static vector allWorkers; 35 | static vector threads; 36 | 37 | public: 38 | static bool init(int workers); 39 | static bool stop(); 40 | static void addRequest(AbstractRequest* request); 41 | static bool addWorker(Worker* worker); 42 | }; 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /Chapter06/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | main.cpp - Main file for the Dispatcher demo application. 3 | 4 | Revision 0 5 | 6 | Features: 7 | - 8 | 9 | Notes: 10 | - 11 | 12 | 2016/11/19, Maya Posch 13 | (c) Nyanko.ws 14 | */ 15 | 16 | 17 | #include "dispatcher.h" 18 | #include "request.h" 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | using namespace std; 27 | 28 | 29 | // Globals 30 | sig_atomic_t signal_caught = 0; 31 | mutex logMutex; 32 | 33 | 34 | void sigint_handler(int sig) { 35 | signal_caught = 1; 36 | } 37 | 38 | 39 | void logFnc(string text) { 40 | logMutex.lock(); 41 | cout << text << "\n"; 42 | logMutex.unlock(); 43 | } 44 | 45 | 46 | int main() { 47 | // Install signal handler. 48 | signal(SIGINT, &sigint_handler); 49 | 50 | // Initialise the dispatcher with 10 worker threads. 51 | Dispatcher::init(10); 52 | 53 | cout << "Initialised.\n"; 54 | 55 | // Generate requests in a continuous loop until terminated with SIGINT or 56 | // limit has been reached. 57 | int cycles = 0; 58 | Request* rq = 0; 59 | while (!signal_caught && cycles < 50) { 60 | rq = new Request(); 61 | rq->setValue(cycles); 62 | rq->setOutput(&logFnc); 63 | Dispatcher::addRequest(rq); 64 | cycles++; 65 | } 66 | 67 | this_thread::sleep_for(chrono::seconds(5)); 68 | 69 | // Cleanup. 70 | Dispatcher::stop(); 71 | cout << "Clean-up done.\n"; 72 | 73 | return 0; 74 | } 75 | -------------------------------------------------------------------------------- /Chapter06/request.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | request.cpp - implementation of the Request class. 3 | 4 | Revision 0 5 | 6 | Notes: 7 | - 8 | 9 | 2016/11/19, Maya Posch 10 | (c) Nyanko.ws 11 | */ 12 | 13 | 14 | #include "request.h" 15 | 16 | 17 | // --- PROCESS --- 18 | void Request::process() { 19 | outFnc("Starting processing request " + std::to_string(value) + "..."); 20 | 21 | // 22 | } 23 | 24 | 25 | // --- FINISH --- 26 | void Request::finish() { 27 | outFnc("Finished request " + std::to_string(value)); 28 | } 29 | -------------------------------------------------------------------------------- /Chapter06/request.h: -------------------------------------------------------------------------------- 1 | /* 2 | request.h - header file for the Request class. 3 | 4 | Revision 0 5 | 6 | Notes: 7 | - 8 | 9 | 2016/11/19, Maya Posch 10 | (c) Nyanko.ws 11 | */ 12 | 13 | 14 | #pragma once 15 | #ifndef REQUEST_H 16 | #define REQUEST_H 17 | 18 | #include "abstract_request.h" 19 | 20 | 21 | #include 22 | 23 | using namespace std; 24 | 25 | 26 | typedef void (*logFunction)(string text); 27 | 28 | 29 | class Request : public AbstractRequest { 30 | int value; 31 | logFunction outFnc; 32 | 33 | public: 34 | void setValue(int value) { this->value = value; } 35 | void setOutput(logFunction fnc) { outFnc = fnc; } 36 | void process(); 37 | void finish(); 38 | }; 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /Chapter06/worker.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | worker.cpp - Implementation of the Worker class. 3 | 4 | Revision 0 5 | 6 | Features: 7 | - 8 | 9 | Notes: 10 | - 11 | 12 | 2016/11/19, Maya Posch 13 | (c) Nyanko.ws 14 | */ 15 | 16 | 17 | #include "worker.h" 18 | #include "dispatcher.h" 19 | 20 | #include 21 | 22 | using namespace std; 23 | 24 | 25 | // --- GET CONDITION --- 26 | void Worker::getCondition(condition_variable* &cv) { 27 | cv = &(this)->cv; 28 | } 29 | 30 | 31 | // --- RUN --- 32 | // Runs the worker instance. 33 | void Worker::run() { 34 | while (running) { 35 | if (ready) { 36 | // Execute the request. 37 | ready = false; 38 | request->process(); 39 | request->finish(); 40 | } 41 | 42 | // Add self to Dispatcher queue and execute next request or wait. 43 | if (Dispatcher::addWorker(this)) { 44 | // Use the ready loop to deal with spurious wake-ups. 45 | while (!ready && running) { 46 | if (cv.wait_for(ulock, chrono::seconds(1)) == cv_status::timeout) { 47 | // We timed out, but we keep waiting unless the worker is 48 | // stopped by the dispatcher. 49 | } 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Chapter06/worker.h: -------------------------------------------------------------------------------- 1 | /* 2 | worker.h - Header file for the Worker class. 3 | 4 | Revision 0 5 | 6 | Notes: 7 | - 8 | 9 | 2016/11/19, Maya Posch 10 | (c) Nyanko.ws 11 | */ 12 | 13 | 14 | #pragma once 15 | #ifndef WORKER_H 16 | #define WORKER_H 17 | 18 | #include "abstract_request.h" 19 | 20 | #include 21 | #include 22 | 23 | using namespace std; 24 | 25 | 26 | class Worker { 27 | condition_variable cv; 28 | mutex mtx; 29 | unique_lock ulock; 30 | AbstractRequest* request; 31 | bool running; 32 | bool ready; 33 | 34 | public: 35 | Worker() { running = true; ready = false; ulock = unique_lock(mtx); } 36 | void run(); 37 | void stop() { running = false; } 38 | void setRequest(AbstractRequest* request) { this->request = request; ready = true; } 39 | void getCondition(condition_variable* &cv); 40 | }; 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /Chapter07/Makefile: -------------------------------------------------------------------------------- 1 | 2 | GCC := g++ 3 | 4 | OUTPUT := dispatcher_demo 5 | SOURCES := $(wildcard *.cpp) 6 | CCFLAGS := -std=c++11 -g3 7 | 8 | all: $(OUTPUT) 9 | 10 | $(OUTPUT): 11 | $(GCC) -o $(OUTPUT) $(CCFLAGS) $(SOURCES) 12 | 13 | clean: 14 | rm $(OUTPUT) 15 | 16 | .PHONY: all 17 | -------------------------------------------------------------------------------- /Chapter07/abstract_request.h: -------------------------------------------------------------------------------- 1 | /* 2 | abstractrequest.h - header file for the AbstractRequest class. 3 | 4 | Revision 0 5 | 6 | Notes: 7 | - 8 | 9 | 2016/11/19, Maya Posch 10 | (c) Nyanko.ws 11 | */ 12 | 13 | 14 | #pragma once 15 | #ifndef ABSTRACT_REQUEST_H 16 | #define ABSTRACT_REQUEST_H 17 | 18 | 19 | class AbstractRequest { 20 | // 21 | 22 | public: 23 | virtual void setValue(int value) = 0; 24 | virtual void process() = 0; 25 | virtual void finish() = 0; 26 | }; 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /Chapter07/dispatcher.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | dispatcher.cpp - Implementation of the Dispatcher class. 3 | 4 | Revision 0 5 | 6 | Features: 7 | - 8 | 9 | Notes: 10 | - 11 | 12 | 2016/11/19, Maya Posch 13 | (c) Nyanko.ws 14 | */ 15 | 16 | 17 | #include "dispatcher.h" 18 | 19 | #include 20 | using namespace std; 21 | 22 | 23 | // Static initialisations. 24 | queue Dispatcher::requests; 25 | queue Dispatcher::workers; 26 | mutex Dispatcher::requestsMutex; 27 | mutex Dispatcher::workersMutex; 28 | vector Dispatcher::allWorkers; 29 | vector Dispatcher::threads; 30 | 31 | 32 | // --- INIT --- 33 | // Start the number of requested worker threads. 34 | bool Dispatcher::init(int workers) { 35 | thread* t = 0; 36 | Worker* w = 0; 37 | for (int i = 0; i < workers; ++i) { 38 | w = new Worker; 39 | allWorkers.push_back(w); 40 | t = new thread(&Worker::run, w); 41 | threads.push_back(t); 42 | } 43 | 44 | return true; 45 | } 46 | 47 | 48 | // --- STOP --- 49 | // Terminate the worker threads and clean up. 50 | bool Dispatcher::stop() { 51 | for (int i = 0; i < allWorkers.size(); ++i) { 52 | allWorkers[i]->stop(); 53 | } 54 | cout << "Stopped workers.\n"; 55 | for (int j = 0; j < threads.size(); ++j) { 56 | threads[j]->join(); 57 | cout << "Joined threads.\n"; 58 | } 59 | } 60 | 61 | 62 | // --- ADD REQUEST --- 63 | void Dispatcher::addRequest(AbstractRequest* request) { 64 | workersMutex.lock(); 65 | if (!workers.empty()) { 66 | Worker* worker = workers.front(); 67 | worker->setRequest(request); 68 | condition_variable* cv; 69 | mutex* mtx; 70 | worker->getCondition(cv); 71 | worker->getMutex(mtx); 72 | unique_lock lock(*mtx); 73 | cv->notify_one(); 74 | workers.pop(); 75 | workersMutex.unlock(); 76 | } 77 | else { 78 | workersMutex.unlock(); 79 | requestsMutex.lock(); 80 | requests.push(request); 81 | requestsMutex.unlock(); 82 | } 83 | } 84 | 85 | 86 | // --- ADD WORKER --- 87 | bool Dispatcher::addWorker(Worker* worker) { 88 | bool wait = true; 89 | requestsMutex.lock(); 90 | if (!requests.empty()) { 91 | AbstractRequest* request = requests.front(); 92 | worker->setRequest(request); 93 | requests.pop(); 94 | wait = false; 95 | requestsMutex.unlock(); 96 | } 97 | else { 98 | requestsMutex.unlock(); 99 | workersMutex.lock(); 100 | workers.push(worker); 101 | workersMutex.unlock(); 102 | } 103 | return wait; 104 | } 105 | -------------------------------------------------------------------------------- /Chapter07/dispatcher.h: -------------------------------------------------------------------------------- 1 | /* 2 | dispatcher.h - header file for the Dispatcher class. 3 | 4 | Revision 0 5 | 6 | Notes: 7 | - 8 | 9 | 2016/11/19, Maya Posch 10 | (c) Nyanko.ws. 11 | */ 12 | 13 | 14 | #pragma once 15 | #ifndef DISPATCHER_H 16 | #define DISPATCHER_H 17 | 18 | #include "abstract_request.h" 19 | #include "worker.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | using namespace std; 27 | 28 | 29 | class Dispatcher { 30 | static queue requests; 31 | static queue workers; 32 | static mutex requestsMutex; 33 | static mutex workersMutex; 34 | static vector allWorkers; 35 | static vector threads; 36 | 37 | public: 38 | static bool init(int workers); 39 | static bool stop(); 40 | static void addRequest(AbstractRequest* request); 41 | static bool addWorker(Worker* worker); 42 | }; 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /Chapter07/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | main.cpp - Main file for the Dispatcher demo application. 3 | 4 | Revision 0 5 | 6 | Features: 7 | - 8 | 9 | Notes: 10 | - 11 | 12 | 2016/11/19, Maya Posch 13 | (c) Nyanko.ws 14 | */ 15 | 16 | 17 | #include "dispatcher.h" 18 | #include "request.h" 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | using namespace std; 27 | 28 | 29 | // Globals 30 | sig_atomic_t signal_caught = 0; 31 | mutex logMutex; 32 | 33 | 34 | void sigint_handler(int sig) { 35 | signal_caught = 1; 36 | } 37 | 38 | 39 | void logFnc(string text) { 40 | logMutex.lock(); 41 | cout << text << "\n"; 42 | logMutex.unlock(); 43 | } 44 | 45 | 46 | int main() { 47 | // Install signal handler. 48 | signal(SIGINT, &sigint_handler); 49 | 50 | // Initialise the dispatcher with 10 worker threads. 51 | Dispatcher::init(10); 52 | 53 | cout << "Initialised.\n"; 54 | 55 | // Generate requests in a continuous loop until terminated with SIGINT or 56 | // limit has been reached. 57 | int cycles = 0; 58 | Request* rq = 0; 59 | while (!signal_caught && cycles < 50) { 60 | rq = new Request(); 61 | rq->setValue(cycles); 62 | rq->setOutput(&logFnc); 63 | Dispatcher::addRequest(rq); 64 | cycles++; 65 | } 66 | 67 | this_thread::sleep_for(chrono::seconds(5)); 68 | 69 | // Cleanup. 70 | Dispatcher::stop(); 71 | cout << "Clean-up done.\n"; 72 | 73 | return 0; 74 | } 75 | -------------------------------------------------------------------------------- /Chapter07/request.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | request.cpp - implementation of the Request class. 3 | 4 | Revision 0 5 | 6 | Notes: 7 | - 8 | 9 | 2016/11/19, Maya Posch 10 | (c) Nyanko.ws 11 | */ 12 | 13 | 14 | #include "request.h" 15 | 16 | 17 | // --- PROCESS --- 18 | void Request::process() { 19 | outFnc("Starting processing request " + std::to_string(value) + "..."); 20 | 21 | // 22 | } 23 | 24 | 25 | // --- FINISH --- 26 | void Request::finish() { 27 | outFnc("Finished request " + std::to_string(value)); 28 | } 29 | -------------------------------------------------------------------------------- /Chapter07/request.h: -------------------------------------------------------------------------------- 1 | /* 2 | request.h - header file for the Request class. 3 | 4 | Revision 0 5 | 6 | Notes: 7 | - 8 | 9 | 2016/11/19, Maya Posch 10 | (c) Nyanko.ws 11 | */ 12 | 13 | 14 | #pragma once 15 | #ifndef REQUEST_H 16 | #define REQUEST_H 17 | 18 | #include "abstract_request.h" 19 | 20 | 21 | #include 22 | 23 | using namespace std; 24 | 25 | 26 | typedef void (*logFunction)(string text); 27 | 28 | 29 | class Request : public AbstractRequest { 30 | int value; 31 | logFunction outFnc; 32 | 33 | public: 34 | void setValue(int value) { this->value = value; } 35 | void setOutput(logFunction fnc) { outFnc = fnc; } 36 | void process(); 37 | void finish(); 38 | }; 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /Chapter07/worker.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | worker.cpp - Implementation of the Worker class. 3 | 4 | Revision 0 5 | 6 | Features: 7 | - 8 | 9 | Notes: 10 | - 11 | 12 | 2016/11/19, Maya Posch 13 | (c) Nyanko.ws 14 | */ 15 | 16 | 17 | #include "worker.h" 18 | #include "dispatcher.h" 19 | 20 | #include 21 | 22 | using namespace std; 23 | 24 | 25 | // --- GET CONDITION --- 26 | void Worker::getCondition(condition_variable* &cv) { 27 | cv = &(this)->cv; 28 | } 29 | 30 | 31 | // --- RUN --- 32 | // Runs the worker instance. 33 | void Worker::run() { 34 | while (running) { 35 | if (ready) { 36 | ready = false; 37 | request->process(); 38 | request->finish(); 39 | } 40 | if (Dispatcher::addWorker(this)) { 41 | while (!ready && running) { 42 | unique_lock ulock(mtx); 43 | if (cv.wait_for(ulock, chrono::seconds(1)) == cv_status::timeout) { 44 | } 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Chapter07/worker.h: -------------------------------------------------------------------------------- 1 | /* 2 | worker.h - Header file for the Worker class. 3 | 4 | Revision 0 5 | 6 | Notes: 7 | - 8 | 9 | 2016/11/19, Maya Posch 10 | (c) Nyanko.ws 11 | */ 12 | 13 | 14 | #pragma once 15 | #ifndef WORKER_H 16 | #define WORKER_H 17 | 18 | #include "abstract_request.h" 19 | 20 | #include 21 | #include 22 | 23 | using namespace std; 24 | 25 | 26 | class Worker { 27 | condition_variable cv; 28 | mutex mtx; 29 | unique_lock ulock; 30 | AbstractRequest* request; 31 | bool running; 32 | bool ready; 33 | 34 | public: 35 | Worker() { running = true; ready = false; ulock = unique_lock(mtx); } 36 | void run(); 37 | void stop() { running = false; } 38 | void setRequest(AbstractRequest* request) { this->request = request; ready = true; } 39 | void getCondition(condition_variable* &cv); 40 | }; 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /Chapter08/1/Makefile: -------------------------------------------------------------------------------- 1 | 2 | GCC := g++ 3 | 4 | OUTPUT := code1 5 | SOURCES := $(wildcard *.cpp) 6 | CCFLAGS := -std=c++11 7 | 8 | all: $(OUTPUT) 9 | 10 | $(OUTPUT): 11 | $(GCC) $(SOURCES) -o $(OUTPUT) -pthread $(CCFLAGS) 12 | 13 | clean: 14 | rm $(OUTPUT) 15 | 16 | .PHONY: all 17 | -------------------------------------------------------------------------------- /Chapter08/1/code1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-CPP-Multithreading/4ee2b49789f1920260f1135908d0a3cf05f20a9d/Chapter08/1/code1 -------------------------------------------------------------------------------- /Chapter08/1/code1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | std::atomic data; 6 | void worker() { 7 | data.fetch_add(1, std::memory_order_relaxed); 8 | } 9 | 10 | int main() { 11 | std::thread t1(worker); 12 | std::thread t2(worker); 13 | std::thread t3(worker); 14 | std::thread t4(worker); 15 | std::thread t5(worker); 16 | 17 | t1.join(); 18 | t2.join(); 19 | t3.join(); 20 | t4.join(); 21 | t5.join(); 22 | 23 | std::cout << "Count value:" << data << '\n'; 24 | } 25 | -------------------------------------------------------------------------------- /Chapter08/2/Makefile: -------------------------------------------------------------------------------- 1 | 2 | GCC := g++ 3 | 4 | OUTPUT := code1 5 | SOURCES := $(wildcard *.cpp) 6 | CCFLAGS := -std=c++11 7 | 8 | all: $(OUTPUT) 9 | 10 | $(OUTPUT): 11 | $(GCC) $(SOURCES) -o $(OUTPUT) -pthread $(CCFLAGS) 12 | 13 | clean: 14 | rm $(OUTPUT) 15 | 16 | .PHONY: all 17 | -------------------------------------------------------------------------------- /Chapter08/2/code1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-CPP-Multithreading/4ee2b49789f1920260f1135908d0a3cf05f20a9d/Chapter08/2/code1 -------------------------------------------------------------------------------- /Chapter08/2/code1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | const int N = 10000; 9 | std::atomic cnt; 10 | std::vector data(N); 11 | 12 | void reader(int id) { 13 | for (;;) { 14 | int idx = atomic_fetch_sub_explicit(&cnt, 1, std::memory_order_relaxed); 15 | if (idx >= 0) { 16 | std::cout << "reader " << std::to_string(id) << " processed item " 17 | << std::to_string(data[idx]) << '\n'; 18 | } 19 | else { 20 | std::cout << "reader " << std::to_string(id) << " done.\n"; 21 | break; 22 | } 23 | } 24 | } 25 | 26 | int main() { 27 | std::iota(data.begin(), data.end(), 1); 28 | cnt = data.size() - 1; 29 | 30 | std::vector v; 31 | for (int n = 0; n < 10; ++n) { 32 | v.emplace_back(reader, n); 33 | } 34 | 35 | for (std::thread& t : v) { 36 | t.join(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Chapter09/1/1/Makefile: -------------------------------------------------------------------------------- 1 | EXECS=code1 2 | MPICC?=mpicc 3 | 4 | all: ${EXECS} 5 | 6 | mpi_hello_world: code1.c 7 | ${MPICC} -o code1 code1.c 8 | 9 | clean: 10 | rm ${EXECS} 11 | -------------------------------------------------------------------------------- /Chapter09/1/1/mpi_hello_world: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-CPP-Multithreading/4ee2b49789f1920260f1135908d0a3cf05f20a9d/Chapter09/1/1/mpi_hello_world -------------------------------------------------------------------------------- /Chapter09/1/1/mpi_hello_world.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char** argv) { 5 | // Initialize the MPI environment 6 | MPI_Init(NULL, NULL); 7 | 8 | // Get the number of processes 9 | int world_size; 10 | MPI_Comm_size(MPI_COMM_WORLD, &world_size); 11 | 12 | // Get the rank of the process 13 | int world_rank; 14 | MPI_Comm_rank(MPI_COMM_WORLD, &world_rank); 15 | 16 | // Get the name of the processor 17 | char processor_name[MPI_MAX_PROCESSOR_NAME]; 18 | int name_len; 19 | MPI_Get_processor_name(processor_name, &name_len); 20 | 21 | // Print off a hello world message 22 | printf("Hello world from processor %s, rank %d" 23 | " out of %d processors\n", 24 | processor_name, world_rank, world_size); 25 | 26 | // Finalize the MPI environment. 27 | MPI_Finalize(); 28 | } 29 | -------------------------------------------------------------------------------- /Chapter09/1/2/hellohybrid.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char *argv[]) { 6 | int numprocs, rank, len; 7 | char procname[MPI_MAX_PROCESSOR_NAME]; 8 | int tnum = 0, tc = 1; 9 | 10 | MPI_Init(&argc, &argv); 11 | MPI_Comm_size(MPI_COMM_WORLD, &numprocs); 12 | MPI_Comm_rank(MPI_COMM_WORLD, &rank); 13 | MPI_Get_processor_name(procname, &len); 14 | 15 | #pragma omp parallel default(shared) private(tnum, tc) { 16 | np = omp_get_num_threads(); 17 | tnum = omp_get_thread_num(); 18 | printf("Thread %d out of %d from process %d out of %d on %s\n", 19 | tnum, tc, rank, numprocs, procname); 20 | } 21 | 22 | MPI_Finalize(); 23 | } -------------------------------------------------------------------------------- /Chapter10/1/code1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "CL\opencl.h" 4 | 5 | #define NUM_ENTRIES 1024 6 | 7 | int main() { // (int argc, const char * argv[]) { 8 | const char* KernelSource = "fft1D_1024_kernel_src.cl"; 9 | const cl_uint num = 1; 10 | clGetDeviceIDs(0, CL_DEVICE_TYPE_GPU, 0, 0, (cl_uint*) num); 11 | cl_device_id devices[1]; 12 | clGetDeviceIDs(0, CL_DEVICE_TYPE_GPU, num, devices, 0); 13 | cl_context context = clCreateContextFromType(0, CL_DEVICE_TYPE_GPU, 0, 0, 0); 14 | clGetDeviceIDs(0, CL_DEVICE_TYPE_DEFAULT, 1, devices, 0); 15 | cl_command_queue queue = clCreateCommandQueue(context, devices[0], 0, 0); 16 | cl_mem memobjs[] = { clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(float) * 2 * NUM_ENTRIES, 0, 0), 17 | clCreateBuffer(context, CL_MEM_READ_WRITE, sizeof(float) * 2 * NUM_ENTRIES, 0, 0) }; 18 | cl_program program = clCreateProgramWithSource(context, 1, (const char **)& KernelSource, 0, 0); 19 | clBuildProgram(program, 0, 0, 0, 0, 0); 20 | cl_kernel kernel = clCreateKernel(program, "fft1D_1024", 0); 21 | size_t local_work_size[1] = { 256 }; 22 | clSetKernelArg(kernel, 0, sizeof(cl_mem), (void *) &memobjs[0]); 23 | clSetKernelArg(kernel, 1, sizeof(cl_mem), (void *) &memobjs[1]); 24 | clSetKernelArg(kernel, 2, sizeof(float) * (local_work_size[0] + 1) * 16, 0); 25 | clSetKernelArg(kernel, 3, sizeof(float) * (local_work_size[0] + 1) * 16, 0); 26 | size_t global_work_size[1] = { 256 }; 27 | global_work_size[0] = NUM_ENTRIES; 28 | local_work_size[0] = 64; // Nvidia: 192 or 256 29 | clEnqueueNDRangeKernel(queue, kernel, 1, 0, global_work_size, local_work_size, 0, 0, 0); 30 | cl_mem C = clCreateBuffer(context, CL_MEM_WRITE_ONLY, (size), 0, &ret); 31 | cl_int ret = clEnqueueReadBuffer(queue, memobjs[1], CL_TRUE, 0, sizeof(float) * 2 * NUM_ENTRIES, C, 0, 0, 0); 32 | clReleaseMemObject(memobjs[0]); 33 | clReleaseMemObject(memobjs[1]); 34 | clReleaseCommandQueue(queue); 35 | clReleaseKernel(kernel); 36 | clReleaseProgram(program); 37 | clReleaseContext(context); 38 | free(C); 39 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Packt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # Mastering C++ Multithreading 5 | This is the code repository for [Mastering C++ Multithreading](https://www.packtpub.com/application-development/mastering-c-multithreading?utm_source=github&utm_medium=repository&utm_campaign=9781787121706), published by [Packt](https://www.packtpub.com/?utm_source=github). It contains all the supporting project files necessary to work through the book from start to finish. 6 | ## About the Book 7 | Multithreaded applications execute multiple threads in a single processor environment, allowing developers achieve concurrency. This book will teach you the finer points of multithreading and concurrency concepts and how to apply them efficiently in C++. 8 | ## Instructions and Navigation 9 | All of the code is organized into folders. Each folder starts with a number followed by the application name. For example, Chapter02. 10 | 11 | 12 | 13 | The code will look like the following: 14 | ``` 15 | cout_mtx.lock(); 16 | cout << "Thread " << tid << " adding " << rval << ". New value: " << val 17 | << ".\n"; 18 | cout_mtx.unlock(); 19 | values_mtx.lock(); 20 | values.push_back(val); 21 | values_mtx.unlock(); 22 | } 23 | ``` 24 | 25 | To follow the instructions in this book, you will need any OS (Windows, Linux, or macOS) and any C++ compiler installed on your systems. 26 | 27 | ## Related Products 28 | * [Mastering C++ Programming](https://www.packtpub.com/application-development/mastering-c-programming?utm_source=github&utm_medium=repository&utm_campaign=9781786461629) 29 | 30 | * [Mastering C++ Game Development](https://www.packtpub.com/game-development/mastering-c-game-development?utm_source=github&utm_medium=repository&utm_campaign=9781785885808) 31 | 32 | * [C++ Machine Learning](https://www.packtpub.com/big-data-and-business-intelligence/c-machine-learning?utm_source=github&utm_medium=repository&utm_campaign=9781786468406) 33 | 34 | ### Suggestions and Feedback 35 | [Click here](https://docs.google.com/forms/d/e/1FAIpQLSe5qwunkGf6PUvzPirPDtuy1Du5Rlzew23UBp2S-P3wB-GcwQ/viewform) if you have any feedback or suggestions. 36 | ### Download a free PDF 37 | 38 | If you have already purchased a print or Kindle version of this book, you can get a DRM-free PDF version at no cost.
Simply click on the link to claim your free PDF.
39 |

https://packt.link/free-ebook/9781787121706

--------------------------------------------------------------------------------