├── C++ Code ├── Section01 │ ├── Makefile │ ├── sec01_mt_example │ └── sec01_mt_example.cpp ├── Section02 │ └── Dekker's algorithm.cpp ├── Section03 │ ├── Condition variables │ │ └── sec03_mt_example.cpp │ ├── PThreads │ │ └── sec03_mt_example.cpp │ ├── QThread │ │ └── sec03_mt_example.cpp │ ├── QthreadStorage_class.cpp │ ├── Synchronization │ │ └── sec03_mt_example.cpp │ ├── Thread class │ │ └── sec03_mt_exapmle.cpp │ ├── Thread local storage (TLC) │ │ └── sec03_mt_example.cpp │ ├── Thread local storage (TLS) │ │ └── sec03_mt_example.cpp │ ├── Thread management │ │ └── sec03_mt_example.cpp │ └── Thread pool │ │ └── sec03_mt_example.cpp ├── Section04 │ ├── Makefile │ ├── abstract_request.h │ ├── dispatcher.cpp │ ├── dispatcher.h │ ├── dispatcher.log │ ├── dispatcher_demo │ ├── main.cpp │ ├── request.cpp │ ├── request.h │ ├── worker.cpp │ └── worker.h ├── Section05 │ ├── Async │ │ ├── Makefile │ │ ├── code1 │ │ └── code1.cpp │ ├── Code Example.cpp │ ├── Future │ │ └── Code Example.cpp │ ├── Lock guard │ │ └── code1.cpp │ ├── Moving threads │ │ └── Code Example.cpp │ ├── Mutex │ │ ├── code1.cpp │ │ └── code2.cpp │ ├── Non-blocking locking │ │ ├── Makefile │ │ ├── code1 │ │ └── code1.cpp │ ├── Packaged_task │ │ ├── Makefile │ │ ├── code1 │ │ └── code1.cpp │ ├── Passing parameters │ │ └── Code Example.cpp │ ├── Promise │ │ ├── Code Example.cpp │ │ └── Code Example2.cpp │ ├── Sleeping │ │ ├── Makefile │ │ └── code1.cpp │ ├── Swap │ │ ├── Makefile │ │ ├── code1 │ │ └── code1.cpp │ ├── Thread Class │ │ ├── Code Example.cpp │ │ └── Code Example2.cpp │ ├── Thread Id │ │ ├── Makefile │ │ ├── code1 │ │ └── code1.cpp │ └── Unique lock │ │ ├── Code Example.cpp │ │ └── Code Example2.cpp ├── Section06 │ ├── Code sample.cpp │ ├── Error types │ ├── Fishy argument values log file │ ├── Makefile │ ├── abstract_request.h │ ├── dispatcher.cpp │ ├── dispatcher.h │ ├── dispatcher_demo │ ├── dispatcher_drd.log │ ├── dispatcher_helgrind.log │ ├── main.cpp │ ├── request.cpp │ ├── request.h │ ├── thread.cc │ ├── unsyscall │ │ ├── Makefile │ │ ├── unsyscall │ │ └── unsyscall.cpp │ ├── unval.cpp │ ├── unval │ │ ├── Makefile │ │ ├── unval │ │ └── unval.cpp │ ├── worker.cpp │ └── worker.h ├── Section07 │ ├── Code Example.cpp │ ├── Code Example2.cpp │ ├── dispatcher.cpp │ ├── dispatcher_helgrind.log │ ├── worker.cpp │ └── worker.h ├── Section08 │ ├── Code Example 1 │ │ ├── Makefile │ │ ├── code1 │ │ └── code1.cpp │ ├── Code Example 2 │ │ ├── Makefile │ │ ├── code2 │ │ └── code2.cpp │ ├── __atomic built-in methods.cpp │ ├── __sync-prefixed extension.cpp │ └── memory order.cpp ├── Section09 │ ├── Code_Example1.c │ ├── Code_Example2.c │ ├── Code_Example3.c │ ├── MPI_Type_create_struct.c │ ├── mpi_hello_world │ │ ├── mpi_hello_world │ │ └── mpi_hello_world.c │ ├── omp_hello.c │ ├── send_recv.c │ └── send_recv_demo ├── V09707.zip └── mpi │ ├── hello_mpi_world │ ├── hello_mpi_world.c │ ├── hellohybrid │ ├── hellohybrid.c │ └── my_hostfile ├── LICENSE ├── README.md ├── Section01 ├── Makefile ├── sec01_mt_example └── sec01_mt_example.cpp ├── Section02 └── Dekker's algorithm.cpp ├── Section03 ├── Condition variables │ └── sec03_mt_example.cpp ├── PThreads │ └── sec03_mt_example.cpp ├── QThread │ └── sec03_mt_example.cpp ├── QthreadStorage_class.cpp ├── Synchronization │ └── sec03_mt_example.cpp ├── Thread class │ └── sec03_mt_exapmle.cpp ├── Thread local storage (TLC) │ └── sec03_mt_example.cpp ├── Thread local storage (TLS) │ └── sec03_mt_example.cpp ├── Thread management │ └── sec03_mt_example.cpp └── Thread pool │ └── sec03_mt_example.cpp ├── Section06 ├── Code sample.cpp ├── Error types ├── Fishy argument values log file ├── Makefile ├── abstract_request.h ├── dispatcher.cpp ├── dispatcher.h ├── dispatcher_demo ├── dispatcher_drd.log ├── dispatcher_helgrind.log ├── main.cpp ├── request.cpp ├── request.h ├── thread.cc ├── unsyscall │ ├── Makefile │ ├── unsyscall │ └── unsyscall.cpp ├── unval.cpp ├── unval │ ├── Makefile │ ├── unval │ └── unval.cpp ├── worker.cpp └── worker.h ├── Section07 ├── Code Example.cpp ├── Code Example2.cpp ├── dispatcher.cpp ├── dispatcher_helgrind.log ├── worker.cpp └── worker.h ├── Section08 ├── Code Example 1 │ ├── Makefile │ ├── code1 │ └── code1.cpp ├── Code Example 2 │ ├── Makefile │ ├── code2 │ └── code2.cpp ├── __atomic built-in methods.cpp ├── __sync-prefixed extension.cpp └── memory order.cpp ├── Section09 ├── Code_Example1.c ├── Code_Example2.c ├── Code_Example3.c ├── MPI_Type_create_struct.c ├── mpi_hello_world │ ├── mpi_hello_world │ └── mpi_hello_world.c ├── omp_hello.c ├── send_recv.c └── send_recv_demo └── mpi ├── hello_mpi_world ├── hello_mpi_world.c ├── hellohybrid ├── hellohybrid.c └── my_hostfile /C++ Code/Section01/Makefile: -------------------------------------------------------------------------------- 1 | 2 | GCC := g++ 3 | 4 | OUTPUT := sec01_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 | -------------------------------------------------------------------------------- /C++ Code/Section01/sec01_mt_example: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-Multithreading-with-Cplusplus/9b0e5a7beeceb4a7262666fa2465fdda0104c9db/C++ Code/Section01/sec01_mt_example -------------------------------------------------------------------------------- /C++ Code/Section01/sec01_mt_example.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | sec01_mt_example.cpp - main file for the Section01 multithreaded example. 3 | 2016/10/30, Maya Posch 4 | */ 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | // --- Globals 14 | mutex values_mtx; 15 | mutex cout_mtx; 16 | vector values; 17 | 18 | int randGen(const int& min, const int& max) { 19 | static thread_local mt19937 generator(hash()(this_thread::get_id())); 20 | uniform_int_distribution distribution(min, max); 21 | return distribution(generator); 22 | } 23 | 24 | void threadFnc(int tid) { 25 | // Calculate the result. 26 | cout_mtx.lock(); 27 | cout << "Starting thread " << tid << ".\n"; 28 | cout_mtx.unlock(); 29 | 30 | values_mtx.lock(); 31 | int val = values[0]; 32 | values_mtx.unlock(); 33 | 34 | int rval = randGen(0, 10); 35 | val += rval; 36 | 37 | cout_mtx.lock(); 38 | cout << "Thread " << tid << " adding " << rval << ". New value: " << val << ".\n"; 39 | cout_mtx.unlock(); 40 | 41 | values_mtx.lock(); 42 | values.push_back(val); 43 | values_mtx.unlock(); 44 | } 45 | 46 | 47 | int main() { 48 | // Set global data in queue. 49 | values.push_back(42); 50 | 51 | // Start the threads, wait for them to finish. 52 | thread tr1(threadFnc, 1); 53 | thread tr2(threadFnc, 2); 54 | thread tr3(threadFnc, 3); 55 | thread tr4(threadFnc, 4); 56 | 57 | tr1.join(); 58 | tr2.join(); 59 | tr3.join(); 60 | tr4.join(); 61 | 62 | // Read the calculated values. 63 | cout << "Input: " << values[0] << ", Result 1: " << values[1] << ", Result 2: " << values[2] << ", Result 3: " << values[3] << ", Result 4: " << values[4] << "\n"; 64 | 65 | return 1; 66 | } 67 | -------------------------------------------------------------------------------- /C++ Code/Section02/Dekker's algorithm.cpp: -------------------------------------------------------------------------------- 1 | variables 2 | wants_to_enter : array of 2 booleans 3 | turn : integer 4 | 5 | wants_to_enter[0] ← false 6 | wants_to_enter[1] ← false 7 | turn ← 0 // or 1 8 | 9 | p0: 10 | wants_to_enter[0] ← true 11 | while wants_to_enter[1] { 12 | if turn ≠ 0 { 13 | wants_to_enter[0] ← false 14 | while turn ≠ 0 { 15 | // busy wait 16 | } 17 | wants_to_enter[0] ← true 18 | } 19 | } 20 | // critical section 21 | ... 22 | turn ← 1 23 | wants_to_enter[0] ← false 24 | // remainder section 25 | 26 | p1: 27 | wants_to_enter[1] ← true 28 | while wants_to_enter[0] { 29 | if turn ≠ 1 { 30 | wants_to_enter[1] ← false 31 | while turn ≠ 1 { 32 | // busy wait 33 | } 34 | wants_to_enter[1] ← true 35 | } 36 | } 37 | // critical section 38 | ... 39 | turn ← 0 40 | wants_to_enter[1] ← false 41 | // remainder section 42 | -------------------------------------------------------------------------------- /C++ Code/Section03/Condition variables/sec03_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 | } 63 | -------------------------------------------------------------------------------- /C++ Code/Section03/PThreads/sec03_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 | -------------------------------------------------------------------------------- /C++ Code/Section03/QThread/sec03_mt_example.cpp: -------------------------------------------------------------------------------- 1 | class Worker : public QObject { 2 | Q_OBJECT 3 | public: 4 | Worker(); 5 | ~Worker(); 6 | public slots: 7 | void process(); 8 | signals: 9 | void finished(); 10 | void error(QString err); 11 | private: 12 | }; 13 | 14 | Worker::Worker() { } 15 | Worker::~Worker() { } 16 | void Worker::process() { 17 | qDebug("Hello World!"); 18 | emit finished(); 19 | } 20 | 21 | QThread* thread = new QThread; 22 | Worker* worker = new Worker(); 23 | worker->moveToThread(thread); 24 | connect(worker, SIGNAL(error(QString)), this, SLOT(errorString(QString))); 25 | connect(thread, SIGNAL(started()), worker, SLOT(process())); 26 | connect(worker, SIGNAL(finished()), thread, SLOT(quit())); 27 | connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater())); 28 | connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); 29 | thread->start(); 30 | -------------------------------------------------------------------------------- /C++ Code/Section03/QthreadStorage_class.cpp: -------------------------------------------------------------------------------- 1 | QThreadStorage > caches; 2 | 3 | void cacheObject(const QString &key, SomeClass* object) { 4 | caches.localData().insert(key, object); 5 | } 6 | 7 | void removeFromCache(const QString &key) { 8 | if (!caches.hasLocalData()) { return; } 9 | 10 | caches.localData().remove(key); 11 | } 12 | -------------------------------------------------------------------------------- /C++ Code/Section03/Synchronization/sec03_mt_example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | int pthread_rwlock_init(pthread_rwlock_t* rwlock, const 3 | pthread_rwlockattr_t* attr); 4 | pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; 5 | 6 | int pthread_rwlock_rdlock(pthread_rwlock_t* rwlock); 7 | int pthread_rwlock_tryrdlock(pthread_rwlock_t* rwlock); 8 | 9 | int pthread_rwlock_wrlock(pthread_rwlock_t* rwlock); 10 | int pthread_rwlock_trywrlock(pthread_rwlock_t * rwlock); 11 | -------------------------------------------------------------------------------- /C++ Code/Section03/Thread class/sec03_mt_exapmle.cpp: -------------------------------------------------------------------------------- 1 | #include "Poco/Thread.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::Thread thread; 14 | thread.start(runnable); 15 | thread.join(); 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /C++ Code/Section03/Thread local storage (TLC)/sec03_mt_example.cpp: -------------------------------------------------------------------------------- 1 | pthread_key_t global_var_key; 2 | void* worker(void* arg) { 3 | int *p = new int; 4 | *p = 1; 5 | pthread_setspecific(global_var_key, p); 6 | int* global_spec_var = (int*) pthread_getspecific(global_var_key); 7 | *global_spec_var += 1 8 | pthread_setspecific(global_var_key, 0); 9 | delete p; 10 | pthread_exit(0); 11 | } 12 | int main(void) { 13 | pthread_t threads[5]; 14 | pthread_key_create(&global_var_key, 0); 15 | for (int i = 0; i < 5; ++i) 16 | pthread_create(&threads[i],0,worker,0); 17 | for (int i = 0; i < 5; ++i) { 18 | pthread_join(threads[i], 0); 19 | } 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /C++ Code/Section03/Thread local storage (TLS)/sec03_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 | } -------------------------------------------------------------------------------- /C++ Code/Section03/Thread management/sec03_mt_example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define MAX_THREADS 3 6 | #define BUF_SIZE 255 7 | 8 | typedef struct MyData { 9 | int val1; 10 | int val2; 11 | } MYDATA, *PMYDATA; 12 | 13 | DWORD WINAPI worker(LPVOID lpParam) { 14 | HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); 15 | if (hStdout == INVALID_HANDLE_VALUE) { 16 | return 1; 17 | } 18 | 19 | PMYDATA pDataArray = (PMYDATA) lpParam; 20 | 21 | TCHAR msgBuf[BUF_SIZE]; 22 | size_t cchStringSize; 23 | DWORD dwChars; 24 | StringCchPrintf(msgBuf, BUF_SIZE, TEXT("Parameters = %d, %dn"), 25 | pDataArray->val1, pDataArray->val2); 26 | StringCchLength(msgBuf, BUF_SIZE, &cchStringSize); 27 | WriteConsole(hStdout, msgBuf, (DWORD) cchStringSize, &dwChars, NULL); 28 | 29 | return 0; 30 | } 31 | 32 | void errorHandler(LPTSTR lpszFunction) { 33 | LPVOID lpMsgBuf; 34 | LPVOID lpDisplayBuf; 35 | DWORD dw = GetLastError(); 36 | 37 | FormatMessage( 38 | FORMAT_MESSAGE_ALLOCATE_BUFFER | 39 | FORMAT_MESSAGE_FROM_SYSTEM | 40 | FORMAT_MESSAGE_IGNORE_INSERTS, 41 | NULL, 42 | dw, 43 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 44 | (LPTSTR) &lpMsgBuf, 45 | 0, NULL); 46 | 47 | lpDisplayBuf = (LPVOID) LocalAlloc(LMEM_ZEROINIT, 48 | (lstrlen((LPCTSTR) lpMsgBuf) + lstrlen((LPCTSTR) lpszFunction) + 49 | 40) * sizeof(TCHAR)); 50 | StringCchPrintf((LPTSTR)lpDisplayBuf, 51 | LocalSize(lpDisplayBuf) / sizeof(TCHAR), 52 | TEXT("%s failed with error %d: %s"), 53 | lpszFunction, dw, lpMsgBuf); 54 | MessageBox(NULL, (LPCTSTR) lpDisplayBuf, TEXT("Error"), MB_OK); 55 | 56 | LocalFree(lpMsgBuf); 57 | LocalFree(lpDisplayBuf); 58 | } 59 | 60 | int _tmain() { 61 | PMYDATA pDataArray[MAX_THREADS]; 62 | DWORD dwThreadIdArray[MAX_THREADS]; 63 | HANDLE hThreadArray[MAX_THREADS]; 64 | for (int i = 0; i < MAX_THREADS; ++i) { 65 | pDataArray[i] = (PMYDATA) HeapAlloc(GetProcessHeap(), 66 | HEAP_ZERO_MEMORY, sizeof(MYDATA)); 67 | if (pDataArray[i] == 0) { 68 | ExitProcess(2); 69 | } 70 | pDataArray[i]->val1 = i; 71 | pDataArray[i]->val2 = i+100; 72 | hThreadArray[i] = CreateThread( 73 | NULL, // default security attributes 74 | 0, // use default stack size 75 | worker, // thread function name 76 | pDataArray[i], // argument to thread function 77 | 0, // use default creation flags 78 | &dwThreadIdArray[i]);// returns the thread identifier 79 | if (hThreadArray[i] == 0) { 80 | errorHandler(TEXT("CreateThread")); 81 | ExitProcess(3); 82 | } 83 | } 84 | WaitForMultipleObjects(MAX_THREADS, hThreadArray, TRUE, INFINITE); 85 | for (int i = 0; i < MAX_THREADS; ++i) { 86 | CloseHandle(hThreadArray[i]); 87 | if (pDataArray[i] != 0) { 88 | HeapFree(GetProcessHeap(), 0, pDataArray[i]); 89 | } 90 | } 91 | return 0; 92 | } 93 | -------------------------------------------------------------------------------- /C++ Code/Section03/Thread pool/sec03_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 | } 17 | -------------------------------------------------------------------------------- /C++ Code/Section04/Makefile: -------------------------------------------------------------------------------- 1 | 2 | GCC := g++ 3 | 4 | OUTPUT := dispatcher_demo 5 | SOURCES := $(wildcard *.cpp) 6 | CCFLAGS := -pthread -std=c++11 -g3 7 | 8 | all: $(OUTPUT) 9 | 10 | $(OUTPUT): 11 | $(GCC) $(SOURCES) -o $(OUTPUT) $(CCFLAGS) 12 | 13 | clean: 14 | rm $(OUTPUT) 15 | 16 | .PHONY: all 17 | -------------------------------------------------------------------------------- /C++ Code/Section04/abstract_request.h: -------------------------------------------------------------------------------- 1 | /* 2 | abstractrequest.h - header file for the AbstractRequest class. 3 | */ 4 | 5 | #pragma once 6 | #ifndef ABSTRACT_REQUEST_H 7 | #define ABSTRACT_REQUEST_H 8 | 9 | class AbstractRequest { 10 | // 11 | 12 | public: 13 | virtual void setValue(int value) = 0; 14 | virtual void process() = 0; 15 | virtual void finish() = 0; 16 | }; 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /C++ Code/Section04/dispatcher.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | dispatcher.cpp - Implementation of the Dispatcher class. 3 | */ 4 | 5 | #include "dispatcher.h" 6 | #include 7 | using namespace std; 8 | 9 | queue Dispatcher::requests; 10 | queue Dispatcher::workers; 11 | mutex Dispatcher::requestsMutex; 12 | mutex Dispatcher::workersMutex; 13 | vector Dispatcher::allWorkers; 14 | vector Dispatcher::threads; 15 | // --- INIT --- 16 | bool Dispatcher::init(int workers) { 17 | thread* t = 0; 18 | Worker* w = 0; 19 | for (int i = 0; i < workers; ++i) { 20 | w = new Worker; 21 | allWorkers.push_back(w); 22 | t = new thread(&Worker::run, w); 23 | threads.push_back(t); 24 | } 25 | return true; 26 | } 27 | // --- STOP --- 28 | bool Dispatcher::stop() { 29 | for (int i = 0; i < allWorkers.size(); ++i) { 30 | allWorkers[i]->stop(); 31 | } 32 | cout << "Stopped workers.\n"; 33 | for (int j = 0; j < threads.size(); ++j) { 34 | threads[j]->join(); 35 | cout << "Joined threads.\n"; 36 | } 37 | 38 | return true; 39 | } 40 | 41 | // --- ADD REQUEST --- 42 | void Dispatcher::addRequest(AbstractRequest* request) { 43 | workersMutex.lock(); 44 | if (!workers.empty()) { 45 | Worker* worker = workers.front(); 46 | worker->setRequest(request); 47 | condition_variable* cv; 48 | worker->getCondition(cv); 49 | cv->notify_one(); 50 | workers.pop(); 51 | workersMutex.unlock(); 52 | } 53 | else { 54 | workersMutex.unlock(); 55 | requestsMutex.lock(); 56 | requests.push(request); 57 | requestsMutex.unlock(); 58 | } 59 | 60 | } 61 | 62 | 63 | // --- ADD WORKER --- 64 | bool Dispatcher::addWorker(Worker* worker) { 65 | 66 | bool wait = true; 67 | requestsMutex.lock(); 68 | if (!requests.empty()) { 69 | AbstractRequest* request = requests.front(); 70 | worker->setRequest(request); 71 | requests.pop(); 72 | wait = false; 73 | requestsMutex.unlock(); 74 | } 75 | else { 76 | requestsMutex.unlock(); 77 | workersMutex.lock(); 78 | workers.push(worker); 79 | workersMutex.unlock(); 80 | } 81 | return wait; 82 | } 83 | -------------------------------------------------------------------------------- /C++ Code/Section04/dispatcher.h: -------------------------------------------------------------------------------- 1 | /* 2 | dispatcher.h - header file for the Dispatcher class. 3 | */ 4 | 5 | #pragma once 6 | #ifndef DISPATCHER_H 7 | #define DISPATCHER_H 8 | 9 | #include "abstract_request.h" 10 | #include "worker.h" 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | using namespace std; 17 | 18 | class Dispatcher { 19 | static queue requests; 20 | static queue workers; 21 | static mutex requestsMutex; 22 | static mutex workersMutex; 23 | static vector allWorkers; 24 | static vector threads; 25 | 26 | public: 27 | static bool init(int workers); 28 | static bool stop(); 29 | static void addRequest(AbstractRequest* request); 30 | static bool addWorker(Worker* worker); 31 | }; 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /C++ Code/Section04/dispatcher.log: -------------------------------------------------------------------------------- 1 | ==12900== Memcheck, a memory error detector 2 | ==12900== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. 3 | ==12900== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info 4 | ==12900== Command: ./dispatcher_demo 5 | ==12900== Parent PID: 9249 6 | ==12900== 7 | ==12900== 8 | ==12900== HEAP SUMMARY: 9 | ==12900== in use at exit: 75,184 bytes in 71 blocks 10 | ==12900== total heap usage: 260 allocs, 189 frees, 88,678 bytes allocated 11 | ==12900== 12 | ==12900== 80 bytes in 10 blocks are definitely lost in loss record 1 of 5 13 | ==12900== at 0x4C2E0EF: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 14 | ==12900== by 0x402EFD: Dispatcher::init(int) (dispatcher.cpp:22) 15 | ==12900== by 0x40930A: main (main.cpp:32) 16 | ==12900== 17 | ==12900== 960 bytes in 40 blocks are definitely lost in loss record 3 of 5 18 | ==12900== at 0x4C2E0EF: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 19 | ==12900== by 0x409342: main (main.cpp:37) 20 | ==12900== 21 | ==12900== 1,440 (1,200 direct, 240 indirect) bytes in 10 blocks are definitely lost in loss record 4 of 5 22 | ==12900== at 0x4C2E0EF: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 23 | ==12900== by 0x402EBB: Dispatcher::init(int) (dispatcher.cpp:20) 24 | ==12900== by 0x40930A: main (main.cpp:32) 25 | ==12900== 26 | ==12900== LEAK SUMMARY: 27 | ==12900== definitely lost: 2,240 bytes in 60 blocks 28 | ==12900== indirectly lost: 240 bytes in 10 blocks 29 | ==12900== possibly lost: 0 bytes in 0 blocks 30 | ==12900== still reachable: 72,704 bytes in 1 blocks 31 | ==12900== suppressed: 0 bytes in 0 blocks 32 | ==12900== Reachable blocks (those to which a pointer was found) are not shown. 33 | ==12900== To see them, rerun with: --leak-check=full --show-leak-kinds=all 34 | ==12900== 35 | ==12900== For counts of detected and suppressed errors, rerun with: -v 36 | ==12900== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0) 37 | -------------------------------------------------------------------------------- /C++ Code/Section04/dispatcher_demo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-Multithreading-with-Cplusplus/9b0e5a7beeceb4a7262666fa2465fdda0104c9db/C++ Code/Section04/dispatcher_demo -------------------------------------------------------------------------------- /C++ Code/Section04/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | main.cpp - Main file for the Dispatcher demo application. 3 | */ 4 | 5 | #include "dispatcher.h" 6 | #include "request.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | 16 | sig_atomic_t signal_caught = 0; 17 | mutex logMutex; 18 | 19 | void sigint_handler(int sig) { 20 | signal_caught = 1; 21 | } 22 | 23 | void logFnc(string text) { 24 | logMutex.lock(); 25 | cout << text << "\n"; 26 | logMutex.unlock(); 27 | } 28 | 29 | 30 | int main() { 31 | signal(SIGINT, &sigint_handler); 32 | Dispatcher::init(10); 33 | cout << "Initialised.\n"; 34 | int cycles = 0; 35 | Request* rq = 0; 36 | while (!signal_caught && cycles < 50) { 37 | rq = new Request(); 38 | rq->setValue(cycles); 39 | rq->setOutput(&logFnc); 40 | Dispatcher::addRequest(rq); 41 | cycles++; 42 | } 43 | 44 | this_thread::sleep_for(chrono::seconds(5)); 45 | // Cleanup. 46 | Dispatcher::stop(); 47 | cout << "Clean-up done.\n"; 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /C++ Code/Section04/request.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | request.cpp - implementation of the Request class. 3 | */ 4 | 5 | #include "request.h" 6 | void Request::process() { 7 | outFnc("Starting processing request " + std::to_string(value) + "..."); 8 | // 9 | } 10 | void Request::finish() { 11 | outFnc("Finished request " + std::to_string(value)); 12 | } 13 | -------------------------------------------------------------------------------- /C++ Code/Section04/request.h: -------------------------------------------------------------------------------- 1 | /* 2 | request.h - header file for the Request class. 3 | */ 4 | 5 | #pragma once 6 | #ifndef REQUEST_H 7 | #define REQUEST_H 8 | 9 | #include "abstract_request.h" 10 | 11 | #include 12 | 13 | using namespace std; 14 | 15 | typedef void (*logFunction)(string text); 16 | 17 | class Request : public AbstractRequest { 18 | int value; 19 | logFunction outFnc; 20 | public: 21 | void setValue(int value) { this->value = value; } 22 | void setOutput(logFunction fnc) { outFnc = fnc; } 23 | void process(); 24 | void finish(); 25 | }; 26 | #endif 27 | -------------------------------------------------------------------------------- /C++ Code/Section04/worker.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | worker.cpp - Implementation of the Worker class. 3 | */ 4 | 5 | #include "worker.h" 6 | #include "dispatcher.h" 7 | #include 8 | 9 | using namespace std; 10 | 11 | void Worker::getCondition(condition_variable* &cv) { 12 | cv = &(this)->cv; 13 | } 14 | 15 | void Worker::run() { 16 | while (running) { 17 | if (ready) { 18 | // Execute the request. 19 | ready = false; 20 | request->process(); 21 | request->finish(); 22 | } 23 | 24 | if (Dispatcher::addWorker(this)) { 25 | // Use the ready loop to deal with spurious wake-ups. 26 | while (!ready && running) { 27 | if (cv.wait_for(ulock, chrono::seconds(1)) == cv_status::timeout) { 28 | // We timed out, but we keep waiting unless the worker is 29 | // stopped by the dispatcher. 30 | } 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /C++ Code/Section04/worker.h: -------------------------------------------------------------------------------- 1 | /* 2 | worker.h - Header file for the Worker class. 3 | */ 4 | 5 | #pragma once 6 | #ifndef WORKER_H 7 | #define WORKER_H 8 | 9 | #include "abstract_request.h" 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | class Worker { 16 | condition_variable cv; 17 | mutex mtx; 18 | unique_lock ulock; 19 | AbstractRequest* request; 20 | bool running; 21 | bool ready; 22 | 23 | public: 24 | Worker() { running = true; ready = false; ulock = unique_lock(mtx); } 25 | void run(); 26 | void stop() { running = false; } 27 | void setRequest(AbstractRequest* request) { this->request = request; ready = true; } 28 | void getCondition(condition_variable* &cv); 29 | }; 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /C++ Code/Section05/Async/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 | -------------------------------------------------------------------------------- /C++ Code/Section05/Async/code1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-Multithreading-with-Cplusplus/9b0e5a7beeceb4a7262666fa2465fdda0104c9db/C++ Code/Section05/Async/code1 -------------------------------------------------------------------------------- /C++ Code/Section05/Async/code1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | bool is_prime (int x) { 6 | cout << "Calculating prime...\n"; 7 | for (int i = 2; i < x; ++i) { 8 | if (x % i == 0) { 9 | return false; 10 | } 11 | } 12 | return true; 13 | } 14 | 15 | int main () { 16 | future pFuture = std::async (is_prime, 343321); 17 | cout << "Checking whether 343321 is a prime number.\n"; 18 | bool result = pFuture.get(); 19 | if (result) { 20 | cout << "Prime found.\n"; 21 | } 22 | else { 23 | cout << "No prime found.\n"; 24 | } 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /C++ Code/Section05/Code Example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | mutex m; 6 | condition_variable cv; 7 | bool ready = false; 8 | ThreadLocal result; 9 | 10 | void worker() { 11 | unique_lock ulock(m); 12 | result = thread_local_method(); 13 | ready = true; 14 | std::notify_all_at_thread_exit(cv, std::move(ulock)); 15 | } 16 | 17 | int main() { 18 | thread t(worker); 19 | t.detach(); 20 | // Do work here. 21 | unique_lock ulock(m); 22 | while(!ready) { 23 | cv.wait(ulock); 24 | } 25 | // Process result 26 | } 27 | -------------------------------------------------------------------------------- /C++ Code/Section05/Future/Code Example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | bool is_prime (int x) { 6 | for (int i = 2; i < x; ++i) if (x%i==0) return false; 7 | return true; 8 | } 9 | 10 | int main () { 11 | std::future fut = std::async (is_prime, 444444443); 12 | std::cout << "Checking, please wait"; 13 | std::chrono::milliseconds span(100); 14 | while (fut.wait_for(span) == std::future_status::timeout) { 15 | std::cout << '.' << std::flush; 16 | } 17 | 18 | bool x = fut.get(); 19 | std::cout << "\n444444443 " << (x?"is":"is not") << " prime.\n"; 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /C++ Code/Section05/Lock guard/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 | std::cout << std::this_thread::get_id() << ": " << counter << '\n'; 15 | } 16 | 17 | int main() { 18 | std::cout << __func__ << ": " << counter << '\n'; 19 | std::thread t1(worker); 20 | std::thread t2(worker); 21 | t1.join(); 22 | t2.join(); 23 | std::cout << __func__ << ": " << counter << '\n'; 24 | } 25 | -------------------------------------------------------------------------------- /C++ Code/Section05/Moving threads/Code Example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void worker(int n, string t) { 6 | // Business logic. 7 | } 8 | 9 | int main () { 10 | std::string s = "Test"; 11 | std::thread t0(worker, 1, s); 12 | std::thread t1(std::move(t0)); 13 | t1.join(); 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /C++ Code/Section05/Mutex/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 | t1.join(); 12 | t2.join(); 13 | 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /C++ Code/Section05/Mutex/code2.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 | t1.join(); 17 | t2.join(); 18 | 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /C++ Code/Section05/Non-blocking locking/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 | -------------------------------------------------------------------------------- /C++ Code/Section05/Non-blocking locking/code1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-Multithreading-with-Cplusplus/9b0e5a7beeceb4a7262666fa2465fdda0104c9db/C++ Code/Section05/Non-blocking locking/code1 -------------------------------------------------------------------------------- /C++ Code/Section05/Non-blocking locking/code1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | std::chrono::milliseconds interval(50); 7 | 8 | std::mutex mutex; 9 | int shared_counter = 0; 10 | int exclusive_counter = 0; 11 | 12 | void worker0() { 13 | std::this_thread::sleep_for(interval); 14 | while (true) { 15 | if (mutex.try_lock()) { 16 | std::cout << "Shared (" << shared_counter << ")\n"; 17 | mutex.unlock(); 18 | return; 19 | } 20 | else { 21 | ++exclusive_counter; 22 | std::cout << "Exclusive (" << exclusive_counter << ")\n"; 23 | std::this_thread::sleep_for(interval); 24 | } 25 | } 26 | } 27 | void worker1() { 28 | mutex.lock(); 29 | std::this_thread::sleep_for(10 * interval); 30 | ++shared_counter; 31 | mutex.unlock(); 32 | } 33 | int main() { 34 | std::thread t1(worker0); 35 | std::thread t2(worker1); 36 | t1.join(); 37 | t2.join(); 38 | } 39 | -------------------------------------------------------------------------------- /C++ Code/Section05/Packaged_task/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 | -------------------------------------------------------------------------------- /C++ Code/Section05/Packaged_task/code1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-Multithreading-with-Cplusplus/9b0e5a7beeceb4a7262666fa2465fdda0104c9db/C++ Code/Section05/Packaged_task/code1 -------------------------------------------------------------------------------- /C++ Code/Section05/Packaged_task/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 | cout << "Finished countdown.\n"; 14 | return from - to; 15 | } 16 | 17 | int main () { 18 | packaged_task task(countdown); 19 | future result = task.get_future(); 20 | thread t (std::move(task), 10, 0); 21 | // Other logic. 22 | int value = result.get(); 23 | cout << "The countdown lasted for " << value << " seconds.\n"; 24 | t.join(); 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /C++ Code/Section05/Passing parameters/Code Example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void worker(int n, std::string t) { 5 | // Business logic. 6 | } 7 | 8 | int main () { 9 | std::string s = "Test"; 10 | int i = 1; 11 | std::thread t(worker, i, s); 12 | t.join(); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /C++ Code/Section05/Promise/Code Example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void print_int (std::future& fut) { 7 | int x = fut.get(); 8 | std::cout << "value: " << x << '\n'; 9 | } 10 | 11 | int main () { 12 | std::promise prom; 13 | std::future fut = prom.get_future(); 14 | std::thread th1 (print_int, std::ref(fut)); 15 | prom.set_value (10); 16 | th1.join(); 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /C++ Code/Section05/Promise/Code Example2.cpp: -------------------------------------------------------------------------------- 1 | //Creating a shared_future 2 | 3 | std::promise promise1; 4 | std::shared_future sFuture(promise1.get_future()); 5 | -------------------------------------------------------------------------------- /C++ Code/Section05/Sleeping/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 | -------------------------------------------------------------------------------- /C++ Code/Section05/Sleeping/code1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 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(std::chrono::seconds(2s)); 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 | -------------------------------------------------------------------------------- /C++ Code/Section05/Swap/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 | -------------------------------------------------------------------------------- /C++ Code/Section05/Swap/code1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-Multithreading-with-Cplusplus/9b0e5a7beeceb4a7262666fa2465fdda0104c9db/C++ Code/Section05/Swap/code1 -------------------------------------------------------------------------------- /C++ Code/Section05/Swap/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 | std::swap(t1, t2); 16 | std::cout << "Swapping threads..." << "\n"; 17 | 18 | std::cout << "thread 1 id: " << t1.get_id() << "\n"; 19 | std::cout << "thread 2 id: " << t2.get_id() << "\n"; 20 | t1.swap(t2); 21 | std::cout << "Swapping threads..." << "\n"; 22 | 23 | std::cout << "thread 1 id: " << t1.get_id() << "\n"; 24 | std::cout << "thread 2 id: " << t2.get_id() << "\n"; 25 | t1.join(); 26 | t2.join(); 27 | } 28 | -------------------------------------------------------------------------------- /C++ Code/Section05/Thread Class/Code Example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void worker() { 4 | // Business logic. 5 | } 6 | 7 | int main () { 8 | std::thread t(worker); 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /C++ Code/Section05/Thread Class/Code Example2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void worker() { 4 | // Business logic. 5 | } 6 | 7 | int main () { 8 | std::thread t(worker); 9 | t.join(); 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /C++ Code/Section05/Thread Id/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 | -------------------------------------------------------------------------------- /C++ Code/Section05/Thread Id/code1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-Multithreading-with-Cplusplus/9b0e5a7beeceb4a7262666fa2465fdda0104c9db/C++ Code/Section05/Thread Id/code1 -------------------------------------------------------------------------------- /C++ Code/Section05/Thread Id/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 | -------------------------------------------------------------------------------- /C++ Code/Section05/Unique lock/Code Example.cpp: -------------------------------------------------------------------------------- 1 | std::mutex m1, m2, m3; 2 | std::unique_lock lock1(m1, std::defer_lock); 3 | std::unique_lock lock2(m2, std::try_lock); 4 | std::unique_lock lock3(m3, std::adopt_lock); 5 | -------------------------------------------------------------------------------- /C++ Code/Section05/Unique lock/Code Example2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | std::mutex my_mutex 3 | int count = 0; 4 | int function() { 5 | std::unique_lock lock(my_mutex); 6 | count++; 7 | } 8 | -------------------------------------------------------------------------------- /C++ Code/Section06/Code sample.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #define _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(addr) 3 | ANNOTATE_HAPPENS_BEFORE(addr) 4 | #define _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(addr) 5 | ANNOTATE_HAPPENS_AFTER(addr) 6 | -------------------------------------------------------------------------------- /C++ Code/Section06/Error types: -------------------------------------------------------------------------------- 1 | Invalid read of size 2 | at 0x: (location) 3 | by 0x: (location) 4 | by 0x: (location) 5 | Address 0x 6 | -------------------------------------------------------------------------------- /C++ Code/Section06/Fishy argument values log file: -------------------------------------------------------------------------------- 1 | ==32233== Argument 'size' of function malloc has a fishy (possibly 2 | negative) value: -3 3 | ==32233== at 0x4C2CFA7: malloc (vg_replace_malloc.c:298) 4 | ==32233== by 0x400555: foo (fishy.c:15) 5 | ==32233== by 0x400583: main (fishy.c:23) 6 | -------------------------------------------------------------------------------- /C++ Code/Section06/Makefile: -------------------------------------------------------------------------------- 1 | 2 | GCC := g++ 3 | 4 | OUTPUT := dispatcher_demo 5 | SOURCES := $(wildcard *.cpp) 6 | CCFLAGS := -pthread -std=c++11 -g3 7 | 8 | all: $(OUTPUT) 9 | 10 | $(OUTPUT): 11 | $(GCC) $(SOURCES) -o $(OUTPUT) $(CCFLAGS) 12 | 13 | clean: 14 | rm $(OUTPUT) 15 | 16 | .PHONY: all 17 | -------------------------------------------------------------------------------- /C++ Code/Section06/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 | -------------------------------------------------------------------------------- /C++ Code/Section06/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 | -------------------------------------------------------------------------------- /C++ Code/Section06/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 | -------------------------------------------------------------------------------- /C++ Code/Section06/dispatcher_demo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-Multithreading-with-Cplusplus/9b0e5a7beeceb4a7262666fa2465fdda0104c9db/C++ Code/Section06/dispatcher_demo -------------------------------------------------------------------------------- /C++ Code/Section06/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 | -------------------------------------------------------------------------------- /C++ Code/Section06/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 | -------------------------------------------------------------------------------- /C++ Code/Section06/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 | -------------------------------------------------------------------------------- /C++ Code/Section06/thread.cc: -------------------------------------------------------------------------------- 1 | // thread -*- C++ -*- 2 | 3 | // Copyright (C) 2008-2017 Free Software Foundation, Inc. 4 | // 5 | // This file is part of the GNU ISO C++ Library. This library is free 6 | // software; you can redistribute it and/or modify it under the 7 | // terms of the GNU General Public License as published by the 8 | // Free Software Foundation; either version 3, or (at your option) 9 | // any later version. 10 | 11 | // This library is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | 16 | // Under Section 7 of GPL version 3, you are granted additional 17 | // permissions described in the GCC Runtime Library Exception, version 18 | // 3.1, as published by the Free Software Foundation. 19 | 20 | // You should have received a copy of the GNU General Public License and 21 | // a copy of the GCC Runtime Library Exception along with this program; 22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 | // . 24 | 25 | 26 | #define _GLIBCXX_THREAD_ABI_COMPAT 1 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1) 33 | 34 | #if defined(_GLIBCXX_USE_GET_NPROCS) 35 | # include 36 | # define _GLIBCXX_NPROCS get_nprocs() 37 | #elif defined(_GLIBCXX_USE_PTHREADS_NUM_PROCESSORS_NP) 38 | # define _GLIBCXX_NPROCS pthread_num_processors_np() 39 | #elif defined(_GLIBCXX_USE_SYSCTL_HW_NCPU) 40 | # include 41 | # include 42 | static inline int get_nprocs() 43 | { 44 | int count; 45 | size_t size = sizeof(count); 46 | int mib[] = { CTL_HW, HW_NCPU }; 47 | if (!sysctl(mib, 2, &count, &size, NULL, 0)) 48 | return count; 49 | return 0; 50 | } 51 | # define _GLIBCXX_NPROCS get_nprocs() 52 | #elif defined(_GLIBCXX_USE_SC_NPROCESSORS_ONLN) 53 | # include 54 | # define _GLIBCXX_NPROCS sysconf(_SC_NPROCESSORS_ONLN) 55 | #elif defined(_GLIBCXX_USE_SC_NPROC_ONLN) 56 | # include 57 | # define _GLIBCXX_NPROCS sysconf(_SC_NPROC_ONLN) 58 | #else 59 | # define _GLIBCXX_NPROCS 0 60 | #endif 61 | 62 | #ifndef _GLIBCXX_USE_NANOSLEEP 63 | # ifdef _GLIBCXX_HAVE_SLEEP 64 | # include 65 | # elif defined(_GLIBCXX_HAVE_WIN32_SLEEP) 66 | # include 67 | # else 68 | # error "No sleep function known for this target" 69 | # endif 70 | #endif 71 | 72 | namespace std _GLIBCXX_VISIBILITY(default) 73 | { 74 | extern "C" 75 | { 76 | static void* execute_native_thread_routine(void* __p) 77 | { 78 | thread::_State_ptr __t{ static_cast(__p) }; 79 | __t->_M_run(); 80 | return nullptr; 81 | } 82 | 83 | #if _GLIBCXX_THREAD_ABI_COMPAT 84 | static void* 85 | execute_native_thread_routine_compat(void* __p) 86 | { 87 | thread::_Impl_base* __t = static_cast(__p); 88 | thread::__shared_base_type __local; 89 | // Now that a new thread has been created we can transfer ownership of 90 | // the thread state to a local object, breaking the reference cycle 91 | // created in thread::_M_start_thread. 92 | __local.swap(__t->_M_this_ptr); 93 | __t->_M_run(); 94 | return nullptr; 95 | } 96 | #endif 97 | } // extern "C" 98 | 99 | _GLIBCXX_BEGIN_NAMESPACE_VERSION 100 | 101 | thread::_State::~_State() = default; 102 | 103 | void 104 | thread::join() 105 | { 106 | int __e = EINVAL; 107 | 108 | if (_M_id != id()) 109 | __e = __gthread_join(_M_id._M_thread, 0); 110 | 111 | if (__e) 112 | __throw_system_error(__e); 113 | 114 | _M_id = id(); 115 | } 116 | 117 | void 118 | thread::detach() 119 | { 120 | int __e = EINVAL; 121 | 122 | if (_M_id != id()) 123 | __e = __gthread_detach(_M_id._M_thread); 124 | 125 | if (__e) 126 | __throw_system_error(__e); 127 | 128 | _M_id = id(); 129 | } 130 | 131 | void thread::_M_start_thread(_State_ptr state, void (*)()) 132 | { 133 | const int err = __gthread_create(&_M_id._M_thread, 134 | &execute_native_thread_routine, 135 | state.get()); 136 | if (err) 137 | __throw_system_error(err); 138 | state.release(); 139 | } 140 | 141 | #if _GLIBCXX_THREAD_ABI_COMPAT 142 | void 143 | thread::_M_start_thread(__shared_base_type __b) 144 | { 145 | if (!__gthread_active_p()) 146 | #if __cpp_exceptions 147 | throw system_error(make_error_code(errc::operation_not_permitted), 148 | "Enable multithreading to use std::thread"); 149 | #else 150 | __throw_system_error(int(errc::operation_not_permitted)); 151 | #endif 152 | 153 | _M_start_thread(std::move(__b), nullptr); 154 | } 155 | 156 | void 157 | thread::_M_start_thread(__shared_base_type __b, void (*)()) 158 | { 159 | auto ptr = __b.get(); 160 | // Create a reference cycle that will be broken in the new thread. 161 | ptr->_M_this_ptr = std::move(__b); 162 | int __e = __gthread_create(&_M_id._M_thread, 163 | &execute_native_thread_routine_compat, ptr); 164 | if (__e) 165 | { 166 | ptr->_M_this_ptr.reset(); // break reference cycle, destroying *ptr. 167 | __throw_system_error(__e); 168 | } 169 | } 170 | #endif 171 | 172 | unsigned int 173 | thread::hardware_concurrency() noexcept 174 | { 175 | int __n = _GLIBCXX_NPROCS; 176 | if (__n < 0) 177 | __n = 0; 178 | return __n; 179 | } 180 | 181 | namespace this_thread 182 | { 183 | void 184 | __sleep_for(chrono::seconds __s, chrono::nanoseconds __ns) 185 | { 186 | #ifdef _GLIBCXX_USE_NANOSLEEP 187 | __gthread_time_t __ts = 188 | { 189 | static_cast(__s.count()), 190 | static_cast(__ns.count()) 191 | }; 192 | while (::nanosleep(&__ts, &__ts) == -1 && errno == EINTR) 193 | { } 194 | #elif defined(_GLIBCXX_HAVE_SLEEP) 195 | # ifdef _GLIBCXX_HAVE_USLEEP 196 | ::sleep(__s.count()); 197 | if (__ns.count() > 0) 198 | { 199 | long __us = __ns.count() / 1000; 200 | if (__us == 0) 201 | __us = 1; 202 | ::usleep(__us); 203 | } 204 | # else 205 | ::sleep(__s.count() + (__ns.count() >= 1000000)); 206 | # endif 207 | #elif defined(_GLIBCXX_HAVE_WIN32_SLEEP) 208 | unsigned long ms = __ns.count() / 1000000; 209 | if (__ns.count() > 0 && ms == 0) 210 | ms = 1; 211 | ::Sleep(chrono::milliseconds(__s).count() + ms); 212 | #endif 213 | } 214 | } 215 | 216 | _GLIBCXX_END_NAMESPACE_VERSION 217 | } // namespace std 218 | 219 | #endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1 220 | -------------------------------------------------------------------------------- /C++ Code/Section06/unsyscall/Makefile: -------------------------------------------------------------------------------- 1 | 2 | GCC := g++ 3 | 4 | OUTPUT := unsyscall 5 | SOURCES := $(wildcard *.cpp) 6 | CCFLAGS := -pthread -std=c++11 -g3 7 | 8 | all: $(OUTPUT) 9 | 10 | $(OUTPUT): 11 | $(GCC) $(SOURCES) -o $(OUTPUT) $(CCFLAGS) 12 | 13 | clean: 14 | rm $(OUTPUT) 15 | 16 | .PHONY: all 17 | -------------------------------------------------------------------------------- /C++ Code/Section06/unsyscall/unsyscall: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-Multithreading-with-Cplusplus/9b0e5a7beeceb4a7262666fa2465fdda0104c9db/C++ Code/Section06/unsyscall/unsyscall -------------------------------------------------------------------------------- /C++ Code/Section06/unsyscall/unsyscall.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | char* arr = (char*) malloc(10); 6 | int* arr2 = (int*) malloc(sizeof(int)); 7 | write(1, arr, 10 ); 8 | exit(arr2[0]); 9 | } 10 | -------------------------------------------------------------------------------- /C++ Code/Section06/unval.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | int main() { 4 | int x; 5 | printf ("x = %d\n", x); 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /C++ Code/Section06/unval/Makefile: -------------------------------------------------------------------------------- 1 | 2 | GCC := g++ 3 | 4 | OUTPUT := unval 5 | SOURCES := $(wildcard *.cpp) 6 | CCFLAGS := -pthread -std=c++11 -g3 7 | 8 | all: $(OUTPUT) 9 | 10 | $(OUTPUT): 11 | $(GCC) $(SOURCES) -o $(OUTPUT) $(CCFLAGS) 12 | 13 | clean: 14 | rm $(OUTPUT) 15 | 16 | .PHONY: all 17 | -------------------------------------------------------------------------------- /C++ Code/Section06/unval/unval: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-Multithreading-with-Cplusplus/9b0e5a7beeceb4a7262666fa2465fdda0104c9db/C++ Code/Section06/unval/unval -------------------------------------------------------------------------------- /C++ Code/Section06/unval/unval.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | int x; 6 | printf ("x = %d\n", x); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /C++ Code/Section06/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 | -------------------------------------------------------------------------------- /C++ Code/Section06/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 | -------------------------------------------------------------------------------- /C++ Code/Section07/Code Example.cpp: -------------------------------------------------------------------------------- 1 | bool TAS(bool lock) { 2 | if (lock) { 3 | return true; 4 | } 5 | else { 6 | lock = true; 7 | return false; 8 | } 9 | } 10 | 11 | bool CAS(int* p, int old, int new) { 12 | if (*p != old) { 13 | return false; 14 | } 15 | *p = new; 16 | return true; 17 | } 18 | 19 | volatile bool lock = false; 20 | void critical() { 21 | while (TAS(&lock) == false); 22 | // Critical section 23 | lock = 0; 24 | } 25 | -------------------------------------------------------------------------------- /C++ Code/Section07/Code Example2.cpp: -------------------------------------------------------------------------------- 1 | class Foo { 2 | static std::map strings; 3 | static std::string oneString; 4 | public: 5 | static void init(int a, std::string b, std::string c) { 6 | strings.insert(std::pair(a, b)); 7 | oneString = c; 8 | } 9 | }; 10 | std::map Foo::strings; 11 | std::string Foo::oneString; 12 | 13 | class Bar { 14 | static std::string name; 15 | static std::string initName(); 16 | public: 17 | void init(); 18 | }; 19 | // Static initializations. 20 | std::string Bar::name = Bar::initName(); 21 | 22 | std::string Bar::initName() { 23 | Foo::init(1, "A", "B"); 24 | return "Bar"; 25 | } 26 | 27 | class Foo { 28 | static std::map& strings(); 29 | static std::string oneString; 30 | public: 31 | static void init(int a, std::string b, std::string c) { 32 | static std::map stringsStatic = Foo::strings(); 33 | stringsStatic.insert(std::pair(a, b)); 34 | oneString = c; 35 | } 36 | }; 37 | std::string Foo::oneString; 38 | 39 | std::map& Foo::strings() { 40 | static std::map* stringsStatic = new std::map(); 42 | return *stringsStatic; 43 | } 44 | -------------------------------------------------------------------------------- /C++ Code/Section07/dispatcher.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | dispatcher.cpp - Implementation of the Dispatcher class. 3 | */ 4 | 5 | #include "dispatcher.h" 6 | #include 7 | using namespace std; 8 | 9 | queue Dispatcher::requests; 10 | queue Dispatcher::workers; 11 | mutex Dispatcher::requestsMutex; 12 | mutex Dispatcher::workersMutex; 13 | vector Dispatcher::allWorkers; 14 | vector Dispatcher::threads; 15 | // --- INIT --- 16 | bool Dispatcher::init(int workers) { 17 | thread* t = 0; 18 | Worker* w = 0; 19 | for (int i = 0; i < workers; ++i) { 20 | w = new Worker; 21 | allWorkers.push_back(w); 22 | t = new thread(&Worker::run, w); 23 | threads.push_back(t); 24 | } 25 | return true; 26 | } 27 | // --- STOP --- 28 | bool Dispatcher::stop() { 29 | for (int i = 0; i < allWorkers.size(); ++i) { 30 | allWorkers[i]->stop(); 31 | } 32 | cout << "Stopped workers.\n"; 33 | for (int j = 0; j < threads.size(); ++j) { 34 | threads[j]->join(); 35 | cout << "Joined threads.\n"; 36 | } 37 | 38 | return true; 39 | } 40 | 41 | // --- ADD REQUEST --- 42 | void Dispatcher::addRequest(AbstractRequest* request) { 43 | workersMutex.lock(); 44 | if (!workers.empty()) { 45 | Worker* worker = workers.front(); 46 | worker->setRequest(request); 47 | condition_variable* cv; 48 | worker->getCondition(cv); 49 | cv->notify_one(); 50 | workers.pop(); 51 | workersMutex.unlock(); 52 | } 53 | else { 54 | workersMutex.unlock(); 55 | requestsMutex.lock(); 56 | requests.push(request); 57 | requestsMutex.unlock(); 58 | } 59 | 60 | } 61 | 62 | 63 | // --- ADD WORKER --- 64 | bool Dispatcher::addWorker(Worker* worker) { 65 | 66 | bool wait = true; 67 | requestsMutex.lock(); 68 | if (!requests.empty()) { 69 | AbstractRequest* request = requests.front(); 70 | worker->setRequest(request); 71 | requests.pop(); 72 | wait = false; 73 | requestsMutex.unlock(); 74 | } 75 | else { 76 | requestsMutex.unlock(); 77 | workersMutex.lock(); 78 | workers.push(worker); 79 | workersMutex.unlock(); 80 | } 81 | return wait; 82 | } 83 | -------------------------------------------------------------------------------- /C++ Code/Section07/worker.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | worker.cpp - Implementation of the Worker class. 3 | */ 4 | 5 | #include "worker.h" 6 | #include "dispatcher.h" 7 | #include 8 | 9 | using namespace std; 10 | 11 | void Worker::getCondition(condition_variable* &cv) { 12 | cv = &(this)->cv; 13 | } 14 | 15 | void Worker::run() { 16 | while (running) { 17 | if (ready) { 18 | // Execute the request. 19 | ready = false; 20 | request->process(); 21 | request->finish(); 22 | } 23 | 24 | if (Dispatcher::addWorker(this)) { 25 | // Use the ready loop to deal with spurious wake-ups. 26 | while (!ready && running) { 27 | if (cv.wait_for(ulock, chrono::seconds(1)) == cv_status::timeout) { 28 | // We timed out, but we keep waiting unless the worker is 29 | // stopped by the dispatcher. 30 | } 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /C++ Code/Section07/worker.h: -------------------------------------------------------------------------------- 1 | /* 2 | worker.h - Header file for the Worker class. 3 | */ 4 | 5 | #pragma once 6 | #ifndef WORKER_H 7 | #define WORKER_H 8 | 9 | #include "abstract_request.h" 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | class Worker { 16 | condition_variable cv; 17 | mutex mtx; 18 | unique_lock ulock; 19 | AbstractRequest* request; 20 | bool running; 21 | bool ready; 22 | 23 | public: 24 | Worker() { running = true; ready = false; ulock = unique_lock(mtx); } 25 | void run(); 26 | void stop() { running = false; } 27 | void setRequest(AbstractRequest* request) { this->request = request; ready = true; } 28 | void getCondition(condition_variable* &cv); 29 | }; 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /C++ Code/Section08/Code Example 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 | -------------------------------------------------------------------------------- /C++ Code/Section08/Code Example 1/code1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-Multithreading-with-Cplusplus/9b0e5a7beeceb4a7262666fa2465fdda0104c9db/C++ Code/Section08/Code Example 1/code1 -------------------------------------------------------------------------------- /C++ Code/Section08/Code Example 1/code1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | std::atomic count; 6 | void worker() { 7 | count.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:" << count << '\n'; 24 | } 25 | -------------------------------------------------------------------------------- /C++ Code/Section08/Code Example 2/Makefile: -------------------------------------------------------------------------------- 1 | 2 | GCC := g++ 3 | 4 | OUTPUT := code2 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 | -------------------------------------------------------------------------------- /C++ Code/Section08/Code Example 2/code2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-Multithreading-with-Cplusplus/9b0e5a7beeceb4a7262666fa2465fdda0104c9db/C++ Code/Section08/Code Example 2/code2 -------------------------------------------------------------------------------- /C++ Code/Section08/Code Example 2/code2.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 | int main() { 26 | std::iota(data.begin(), data.end(), 1); 27 | cnt = data.size() - 1; 28 | std::vector v; 29 | for (int n = 0; n < 10; ++n) { 30 | v.emplace_back(reader, n); 31 | } 32 | for (std::thread& t : v) { 33 | t.join(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /C++ Code/Section08/__atomic built-in methods.cpp: -------------------------------------------------------------------------------- 1 | type __atomic_load_n (type *ptr, int memorder) 2 | void __atomic_load (type *ptr, type *ret, int memorder) 3 | void __atomic_store_n (type *ptr, type val, int memorder) 4 | void __atomic_store (type *ptr, type *val, int memorder) 5 | type __atomic_exchange_n (type *ptr, type val, int memorder) 6 | void __atomic_exchange (type *ptr, type *val, type *ret, int memorder) 7 | bool __atomic_compare_exchange_n (type *ptr, type *expected, type desired, 8 | bool weak, int success_memorder, int failure_memorder) 9 | bool __atomic_compare_exchange (type *ptr, type *expected, type *desired, 10 | bool weak, int success_memorder, int failure_memorder) 11 | 12 | type __atomic_add_fetch (type *ptr, type val, int memorder) 13 | type __atomic_sub_fetch (type *ptr, type val, int memorder) 14 | type __atomic_and_fetch (type *ptr, type val, int memorder) 15 | type __atomic_xor_fetch (type *ptr, type val, int memorder) 16 | type __atomic_or_fetch (type *ptr, type val, int memorder) 17 | type __atomic_nand_fetch (type *ptr, type val, int memorder) 18 | 19 | type __atomic_fetch_add (type *ptr, type val, int memorder) 20 | type __atomic_fetch_sub (type *ptr, type val, int memorder) 21 | type __atomic_fetch_and (type *ptr, type val, int memorder) 22 | type __atomic_fetch_xor (type *ptr, type val, int memorder) 23 | type __atomic_fetch_or (type *ptr, type val, int memorder) 24 | type __atomic_fetch_nand (type *ptr, type val, int memorder) 25 | 26 | bool __atomic_test_and_set (void *ptr, int memorder) 27 | 28 | void __atomic_clear (bool *ptr, int memorder) 29 | 30 | void __atomic_thread_fence (int memorder) 31 | 32 | void __atomic_signal_fence (int memorder) 33 | 34 | bool __atomic_always_lock_free (size_t size, void *ptr) 35 | 36 | bool __atomic_is_lock_free (size_t size, void *ptr) 37 | -------------------------------------------------------------------------------- /C++ Code/Section08/__sync-prefixed extension.cpp: -------------------------------------------------------------------------------- 1 | type __sync_fetch_and_add (type *ptr, type value, ...) 2 | type __sync_fetch_and_sub (type *ptr, type value, ...) 3 | type __sync_fetch_and_or (type *ptr, type value, ...) 4 | type __sync_fetch_and_and (type *ptr, type value, ...) 5 | type __sync_fetch_and_xor (type *ptr, type value, ...) 6 | type __sync_fetch_and_nand (type *ptr, type value, ...) 7 | 8 | type __sync_add_and_fetch (type *ptr, type value, ...) 9 | type __sync_sub_and_fetch (type *ptr, type value, ...) 10 | type __sync_or_and_fetch (type *ptr, type value, ...) 11 | type __sync_and_and_fetch (type *ptr, type value, ...) 12 | type __sync_xor_and_fetch (type *ptr, type value, ...) 13 | type __sync_nand_and_fetch (type *ptr, type value, ...) 14 | 15 | bool __sync_bool_compare_and_swap (type *ptr, type oldval, type newval, 16 | ...) 17 | type __sync_val_compare_and_swap (type *ptr, type oldval, type newval, ...) 18 | 19 | __sync_synchronize (...) 20 | 21 | type __sync_lock_test_and_set (type *ptr, type value, ...) 22 | 23 | void __sync_lock_release (type *ptr, ...) 24 | -------------------------------------------------------------------------------- /C++ Code/Section08/memory order.cpp: -------------------------------------------------------------------------------- 1 | enum memory_order { 2 | memory_order_relaxed, 3 | memory_order_consume, 4 | memory_order_acquire, 5 | memory_order_release, 6 | memory_order_acq_rel, 7 | memory_order_seq_cst 8 | }; 9 | -------------------------------------------------------------------------------- /C++ Code/Section09/Code_Example1.c: -------------------------------------------------------------------------------- 1 | int MPI_Send( 2 | void* data, 3 | int count, 4 | MPI_Datatype datatype, 5 | int destination, 6 | int tag, 7 | MPI_Comm communicator) 8 | 9 | int MPI_Recv( 10 | void* data, 11 | int count, 12 | MPI_Datatype datatype, 13 | int source, 14 | int tag, 15 | MPI_Comm communicator, 16 | MPI_Status* status) 17 | -------------------------------------------------------------------------------- /C++ Code/Section09/Code_Example2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | struct car { 7 | int shifts; 8 | int topSpeed; 9 | }; 10 | 11 | int main(int argc, char **argv) { 12 | const int tag = 13; 13 | int size, rank; 14 | MPI_Init(&argc, &argv); 15 | 16 | MPI_Comm_size(MPI_COMM_WORLD, &size); 17 | 18 | if (size < 2) { 19 | fprintf(stderr,"Requires at least two processes.\n"); 20 | MPI_Abort(MPI_COMM_WORLD, 1); 21 | } 22 | 23 | const int nitems = 2; 24 | int blocklengths[2] = {1,1}; 25 | MPI_Datatype types[2] = {MPI_INT, MPI_INT}; 26 | MPI_Datatype mpi_car_type; 27 | MPI_Aint offsets[2]; 28 | 29 | offsets[0] = offsetof(car, shifts); 30 | offsets[1] = offsetof(car, topSpeed); 31 | 32 | MPI_Type_create_struct(nitems, blocklengths, offsets, types, 33 | &mpi_car_type); 34 | MPI_Type_commit(&mpi_car_type); 35 | 36 | MPI_Comm_rank(MPI_COMM_WORLD, &rank); 37 | if (rank == 0) { 38 | car send; 39 | send.shifts = 4; 40 | send.topSpeed = 100; 41 | 42 | const int dest = 1; 43 | MPI_Send(&send, 1, mpi_car_type, dest, tag, MPI_COMM_WORLD); 44 | 45 | printf("Rank %d: sent structure car\n", rank); 46 | } 47 | if (rank == 1) { 48 | MPI_Status status; 49 | const int src = 0; 50 | 51 | car recv; 52 | 53 | MPI_Recv(&recv, 1, mpi_car_type, src, tag, MPI_COMM_WORLD, 54 | &status); 55 | printf("Rank %d: Received: shifts = %d topSpeed = %d\n", rank, 56 | recv.shifts, recv.topSpeed); 57 | } 58 | 59 | MPI_Type_free(&mpi_car_type); 60 | MPI_Finalize(); 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /C++ Code/Section09/Code_Example3.c: -------------------------------------------------------------------------------- 1 | int MPI_Bcast( 2 | void *buffer, 3 | int count, 4 | MPI_Datatype datatype, 5 | int root, 6 | MPI_Comm comm) 7 | 8 | int MPI_Scatter( 9 | void* send_data, 10 | int send_count, 11 | MPI_Datatype send_datatype, 12 | void* recv_data, 13 | int recv_count, 14 | MPI_Datatype recv_datatype, 15 | int root, 16 | MPI_Comm communicator) 17 | 18 | int MPI_Gather( 19 | void* send_data, 20 | int send_count, 21 | MPI_Datatype send_datatype, 22 | void* recv_data, 23 | int recv_count, 24 | MPI_Datatype recv_datatype, 25 | int root, 26 | MPI_Comm communicator) 27 | 28 | 29 | -------------------------------------------------------------------------------- /C++ Code/Section09/MPI_Type_create_struct.c: -------------------------------------------------------------------------------- 1 | int MPI_Type_create_struct( 2 | int count, 3 | int array_of_blocklengths[], 4 | const MPI_Aint array_of_displacements[], 5 | const MPI_Datatype array_of_types[], 6 | MPI_Datatype *newtype) 7 | 8 | -------------------------------------------------------------------------------- /C++ Code/Section09/mpi_hello_world/mpi_hello_world: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-Multithreading-with-Cplusplus/9b0e5a7beeceb4a7262666fa2465fdda0104c9db/C++ Code/Section09/mpi_hello_world/mpi_hello_world -------------------------------------------------------------------------------- /C++ Code/Section09/mpi_hello_world/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 | -------------------------------------------------------------------------------- /C++ Code/Section09/omp_hello.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * FILE: omp_hello.c 3 | * DESCRIPTION: 4 | * OpenMP Example - Hello World - C/C++ Version 5 | * In this simple example, the master thread forks a parallel region. 6 | * All threads in the team obtain their unique thread number and print it. 7 | * The master thread only prints the total number of threads. Two OpenMP 8 | * library routines are used to obtain the number of threads and each 9 | * thread's number. 10 | * AUTHOR: Blaise Barney 5/99 11 | * LAST REVISED: 04/06/05 12 | ******************************************************************************/ 13 | #include 14 | #include 15 | #include 16 | 17 | int main (int argc, char *argv[]) 18 | { 19 | int nthreads, tid; 20 | 21 | #pragma omp parallel private(nthreads, tid) 22 | { 23 | tid = omp_get_thread_num(); 24 | printf("Hello World from thread = %d\n", tid); 25 | 26 | if (tid == 0) 27 | { 28 | nthreads = omp_get_num_threads(); 29 | printf("Number of threads = %d\n", nthreads); 30 | } 31 | } /* All threads join master thread and disband */ 32 | } 33 | -------------------------------------------------------------------------------- /C++ Code/Section09/send_recv.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char** argv) { 6 | MPI_Init(NULL, NULL); 7 | int world_rank; 8 | MPI_Comm_rank(MPI_COMM_WORLD, &world_rank); 9 | int world_size; 10 | MPI_Comm_size(MPI_COMM_WORLD, &world_size); 11 | 12 | if (world_size < 2) { 13 | fprintf(stderr, "World size must be greater than 1 for %s\n", argv[0]); 14 | MPI_Abort(MPI_COMM_WORLD, 1); 15 | } 16 | 17 | int number; 18 | if (world_rank == 0) { 19 | number = -1; 20 | MPI_Send(&number, 1, MPI_INT, 1, 0, MPI_COMM_WORLD); 21 | } 22 | else if (world_rank == 1) { 23 | MPI_Recv(&number, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); 24 | printf("Process 1 received number %d from process 0\n", number); 25 | } 26 | MPI_Finalize(); 27 | } 28 | -------------------------------------------------------------------------------- /C++ Code/Section09/send_recv_demo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-Multithreading-with-Cplusplus/9b0e5a7beeceb4a7262666fa2465fdda0104c9db/C++ Code/Section09/send_recv_demo -------------------------------------------------------------------------------- /C++ Code/V09707.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-Multithreading-with-Cplusplus/9b0e5a7beeceb4a7262666fa2465fdda0104c9db/C++ Code/V09707.zip -------------------------------------------------------------------------------- /C++ Code/mpi/hello_mpi_world: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-Multithreading-with-Cplusplus/9b0e5a7beeceb4a7262666fa2465fdda0104c9db/C++ Code/mpi/hello_mpi_world -------------------------------------------------------------------------------- /C++ Code/mpi/hello_mpi_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 | -------------------------------------------------------------------------------- /C++ Code/mpi/hellohybrid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-Multithreading-with-Cplusplus/9b0e5a7beeceb4a7262666fa2465fdda0104c9db/C++ Code/mpi/hellohybrid -------------------------------------------------------------------------------- /C++ Code/mpi/hellohybrid.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "mpi.h" 3 | #include 4 | 5 | int main(int argc, char *argv[]) { 6 | int numprocs, rank, namelen; 7 | char processor_name[MPI_MAX_PROCESSOR_NAME]; 8 | int iam = 0, np = 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(processor_name, &namelen); 14 | 15 | #pragma omp parallel default(shared) private(iam, np) 16 | { 17 | np = omp_get_num_threads(); 18 | iam = omp_get_thread_num(); 19 | printf("Hello from thread %d out of %d from process %d out of %d on %s\n", 20 | iam, np, rank, numprocs, processor_name); 21 | } 22 | 23 | MPI_Finalize(); 24 | } 25 | -------------------------------------------------------------------------------- /C++ Code/mpi/my_hostfile: -------------------------------------------------------------------------------- 1 | 2 | node1 3 | node2 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 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 | # Mastering Multithreading with C++ [Video] 2 | This is the code repository for [Mastering Multithreading with C++ [Video]](https://www.packtpub.com/application-development/mastering-multithreading-c-video?utm_source=github&utm_medium=repository&utm_campaign=9781788836210), published by [Packt](https://www.packtpub.com/?utm_source=github). It contains all the supporting project files necessary to work through the video course from start to finish. 3 | ## About the Video Course 4 | Multithreaded applications execute multiple threads in a single processor environment, allowing developers achieve concurrency. This video will teach you the finer points of multithreading and concurrency concepts and how to apply them efficiently in C++.Divided into three modules, we start with a brief introduction to the fundamentals of multithreading and concurrency concepts. We then take an in-depth look at how these concepts work at the hardware-level as well as how both operating systems and frameworks use these low-level functions. We’ll also learn about the native multithreading and concurrency support available in C++ since the 2011 revision, synchronization, and communication between threads. 5 | 6 |

What You Will Learn

7 |
8 |
    9 |
  • Go through a basic example of multithreading using the native threading support added in the 2011 revision of C++ 10 |
  • Build upon the fundamentals provided by the hardware implementations 11 |
  • Explore the wide variety of multithreading APIs available as OS-level APIs 12 |
  • Explore an advanced multithreading implementation using C++ 14's native threading API 13 |
  • Extend and optimize thread-safety using the features offered by the full feature set in C++ 11 and C++ 14    
14 | 15 | ## Instructions and Navigation 16 | ### Assumed Knowledge 17 | To fully benefit from the coverage included in this course, you will need:
18 | This course is for intermediate C++ developers who wish to extend their knowledge of multithreading and concurrent processing. You should have basic experience with multithreading and be comfortable using C++ development toolchains on the command line. 19 | ### Technical Requirements 20 | This course has the following software requirements:
21 | C++11 and C++14 22 | 23 | ## Related Products 24 | * [Troubleshooting Vue.js [Video]](https://www.packtpub.com/application-development/troubleshooting-vuejs-video?utm_source=github&utm_medium=repository&utm_campaign=9781788993531) 25 | 26 | * [Angular 7 New Features [Video]](https://www.packtpub.com/web-development/angular-7-new-features-video?utm_source=github&utm_medium=repository&utm_campaign=9781789619683) 27 | 28 | * [Microservices Development on Azure with Java [Video]](https://www.packtpub.com/virtualization-and-cloud/microservices-development-azure-java-video?utm_source=github&utm_medium=repository&utm_campaign=9781789808858) 29 | 30 | -------------------------------------------------------------------------------- /Section01/Makefile: -------------------------------------------------------------------------------- 1 | 2 | GCC := g++ 3 | 4 | OUTPUT := sec01_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 | -------------------------------------------------------------------------------- /Section01/sec01_mt_example: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-Multithreading-with-Cplusplus/9b0e5a7beeceb4a7262666fa2465fdda0104c9db/Section01/sec01_mt_example -------------------------------------------------------------------------------- /Section01/sec01_mt_example.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | sec01_mt_example.cpp - main file for the Section01 multithreaded example. 3 | 2016/10/30, Maya Posch 4 | */ 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | // --- Globals 14 | mutex values_mtx; 15 | mutex cout_mtx; 16 | vector values; 17 | 18 | int randGen(const int& min, const int& max) { 19 | static thread_local mt19937 generator(hash()(this_thread::get_id())); 20 | uniform_int_distribution distribution(min, max); 21 | return distribution(generator); 22 | } 23 | 24 | void threadFnc(int tid) { 25 | // Calculate the result. 26 | cout_mtx.lock(); 27 | cout << "Starting thread " << tid << ".\n"; 28 | cout_mtx.unlock(); 29 | 30 | values_mtx.lock(); 31 | int val = values[0]; 32 | values_mtx.unlock(); 33 | 34 | int rval = randGen(0, 10); 35 | val += rval; 36 | 37 | cout_mtx.lock(); 38 | cout << "Thread " << tid << " adding " << rval << ". New value: " << val << ".\n"; 39 | cout_mtx.unlock(); 40 | 41 | values_mtx.lock(); 42 | values.push_back(val); 43 | values_mtx.unlock(); 44 | } 45 | 46 | 47 | int main() { 48 | // Set global data in queue. 49 | values.push_back(42); 50 | 51 | // Start the threads, wait for them to finish. 52 | thread tr1(threadFnc, 1); 53 | thread tr2(threadFnc, 2); 54 | thread tr3(threadFnc, 3); 55 | thread tr4(threadFnc, 4); 56 | 57 | tr1.join(); 58 | tr2.join(); 59 | tr3.join(); 60 | tr4.join(); 61 | 62 | // Read the calculated values. 63 | cout << "Input: " << values[0] << ", Result 1: " << values[1] << ", Result 2: " << values[2] << ", Result 3: " << values[3] << ", Result 4: " << values[4] << "\n"; 64 | 65 | return 1; 66 | } 67 | -------------------------------------------------------------------------------- /Section02/Dekker's algorithm.cpp: -------------------------------------------------------------------------------- 1 | variables 2 | wants_to_enter : array of 2 booleans 3 | turn : integer 4 | 5 | wants_to_enter[0] ← false 6 | wants_to_enter[1] ← false 7 | turn ← 0 // or 1 8 | 9 | p0: 10 | wants_to_enter[0] ← true 11 | while wants_to_enter[1] { 12 | if turn ≠ 0 { 13 | wants_to_enter[0] ← false 14 | while turn ≠ 0 { 15 | // busy wait 16 | } 17 | wants_to_enter[0] ← true 18 | } 19 | } 20 | // critical section 21 | ... 22 | turn ← 1 23 | wants_to_enter[0] ← false 24 | // remainder section 25 | 26 | p1: 27 | wants_to_enter[1] ← true 28 | while wants_to_enter[0] { 29 | if turn ≠ 1 { 30 | wants_to_enter[1] ← false 31 | while turn ≠ 1 { 32 | // busy wait 33 | } 34 | wants_to_enter[1] ← true 35 | } 36 | } 37 | // critical section 38 | ... 39 | turn ← 0 40 | wants_to_enter[1] ← false 41 | // remainder section 42 | -------------------------------------------------------------------------------- /Section03/Condition variables/sec03_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 | } 63 | -------------------------------------------------------------------------------- /Section03/PThreads/sec03_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 | -------------------------------------------------------------------------------- /Section03/QThread/sec03_mt_example.cpp: -------------------------------------------------------------------------------- 1 | class Worker : public QObject { 2 | Q_OBJECT 3 | public: 4 | Worker(); 5 | ~Worker(); 6 | public slots: 7 | void process(); 8 | signals: 9 | void finished(); 10 | void error(QString err); 11 | private: 12 | }; 13 | 14 | Worker::Worker() { } 15 | Worker::~Worker() { } 16 | void Worker::process() { 17 | qDebug("Hello World!"); 18 | emit finished(); 19 | } 20 | 21 | QThread* thread = new QThread; 22 | Worker* worker = new Worker(); 23 | worker->moveToThread(thread); 24 | connect(worker, SIGNAL(error(QString)), this, SLOT(errorString(QString))); 25 | connect(thread, SIGNAL(started()), worker, SLOT(process())); 26 | connect(worker, SIGNAL(finished()), thread, SLOT(quit())); 27 | connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater())); 28 | connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); 29 | thread->start(); 30 | -------------------------------------------------------------------------------- /Section03/QthreadStorage_class.cpp: -------------------------------------------------------------------------------- 1 | QThreadStorage > caches; 2 | 3 | void cacheObject(const QString &key, SomeClass* object) { 4 | caches.localData().insert(key, object); 5 | } 6 | 7 | void removeFromCache(const QString &key) { 8 | if (!caches.hasLocalData()) { return; } 9 | 10 | caches.localData().remove(key); 11 | } 12 | -------------------------------------------------------------------------------- /Section03/Synchronization/sec03_mt_example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | int pthread_rwlock_init(pthread_rwlock_t* rwlock, const 3 | pthread_rwlockattr_t* attr); 4 | pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; 5 | 6 | int pthread_rwlock_rdlock(pthread_rwlock_t* rwlock); 7 | int pthread_rwlock_tryrdlock(pthread_rwlock_t* rwlock); 8 | 9 | int pthread_rwlock_wrlock(pthread_rwlock_t* rwlock); 10 | int pthread_rwlock_trywrlock(pthread_rwlock_t * rwlock); 11 | -------------------------------------------------------------------------------- /Section03/Thread class/sec03_mt_exapmle.cpp: -------------------------------------------------------------------------------- 1 | #include "Poco/Thread.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::Thread thread; 14 | thread.start(runnable); 15 | thread.join(); 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /Section03/Thread local storage (TLC)/sec03_mt_example.cpp: -------------------------------------------------------------------------------- 1 | pthread_key_t global_var_key; 2 | void* worker(void* arg) { 3 | int *p = new int; 4 | *p = 1; 5 | pthread_setspecific(global_var_key, p); 6 | int* global_spec_var = (int*) pthread_getspecific(global_var_key); 7 | *global_spec_var += 1 8 | pthread_setspecific(global_var_key, 0); 9 | delete p; 10 | pthread_exit(0); 11 | } 12 | int main(void) { 13 | pthread_t threads[5]; 14 | pthread_key_create(&global_var_key, 0); 15 | for (int i = 0; i < 5; ++i) 16 | pthread_create(&threads[i],0,worker,0); 17 | for (int i = 0; i < 5; ++i) { 18 | pthread_join(threads[i], 0); 19 | } 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /Section03/Thread local storage (TLS)/sec03_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 | } -------------------------------------------------------------------------------- /Section03/Thread management/sec03_mt_example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define MAX_THREADS 3 6 | #define BUF_SIZE 255 7 | 8 | typedef struct MyData { 9 | int val1; 10 | int val2; 11 | } MYDATA, *PMYDATA; 12 | 13 | DWORD WINAPI worker(LPVOID lpParam) { 14 | HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); 15 | if (hStdout == INVALID_HANDLE_VALUE) { 16 | return 1; 17 | } 18 | 19 | PMYDATA pDataArray = (PMYDATA) lpParam; 20 | 21 | TCHAR msgBuf[BUF_SIZE]; 22 | size_t cchStringSize; 23 | DWORD dwChars; 24 | StringCchPrintf(msgBuf, BUF_SIZE, TEXT("Parameters = %d, %dn"), 25 | pDataArray->val1, pDataArray->val2); 26 | StringCchLength(msgBuf, BUF_SIZE, &cchStringSize); 27 | WriteConsole(hStdout, msgBuf, (DWORD) cchStringSize, &dwChars, NULL); 28 | 29 | return 0; 30 | } 31 | 32 | void errorHandler(LPTSTR lpszFunction) { 33 | LPVOID lpMsgBuf; 34 | LPVOID lpDisplayBuf; 35 | DWORD dw = GetLastError(); 36 | 37 | FormatMessage( 38 | FORMAT_MESSAGE_ALLOCATE_BUFFER | 39 | FORMAT_MESSAGE_FROM_SYSTEM | 40 | FORMAT_MESSAGE_IGNORE_INSERTS, 41 | NULL, 42 | dw, 43 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 44 | (LPTSTR) &lpMsgBuf, 45 | 0, NULL); 46 | 47 | lpDisplayBuf = (LPVOID) LocalAlloc(LMEM_ZEROINIT, 48 | (lstrlen((LPCTSTR) lpMsgBuf) + lstrlen((LPCTSTR) lpszFunction) + 49 | 40) * sizeof(TCHAR)); 50 | StringCchPrintf((LPTSTR)lpDisplayBuf, 51 | LocalSize(lpDisplayBuf) / sizeof(TCHAR), 52 | TEXT("%s failed with error %d: %s"), 53 | lpszFunction, dw, lpMsgBuf); 54 | MessageBox(NULL, (LPCTSTR) lpDisplayBuf, TEXT("Error"), MB_OK); 55 | 56 | LocalFree(lpMsgBuf); 57 | LocalFree(lpDisplayBuf); 58 | } 59 | 60 | int _tmain() { 61 | PMYDATA pDataArray[MAX_THREADS]; 62 | DWORD dwThreadIdArray[MAX_THREADS]; 63 | HANDLE hThreadArray[MAX_THREADS]; 64 | for (int i = 0; i < MAX_THREADS; ++i) { 65 | pDataArray[i] = (PMYDATA) HeapAlloc(GetProcessHeap(), 66 | HEAP_ZERO_MEMORY, sizeof(MYDATA)); 67 | if (pDataArray[i] == 0) { 68 | ExitProcess(2); 69 | } 70 | pDataArray[i]->val1 = i; 71 | pDataArray[i]->val2 = i+100; 72 | hThreadArray[i] = CreateThread( 73 | NULL, // default security attributes 74 | 0, // use default stack size 75 | worker, // thread function name 76 | pDataArray[i], // argument to thread function 77 | 0, // use default creation flags 78 | &dwThreadIdArray[i]);// returns the thread identifier 79 | if (hThreadArray[i] == 0) { 80 | errorHandler(TEXT("CreateThread")); 81 | ExitProcess(3); 82 | } 83 | } 84 | WaitForMultipleObjects(MAX_THREADS, hThreadArray, TRUE, INFINITE); 85 | for (int i = 0; i < MAX_THREADS; ++i) { 86 | CloseHandle(hThreadArray[i]); 87 | if (pDataArray[i] != 0) { 88 | HeapFree(GetProcessHeap(), 0, pDataArray[i]); 89 | } 90 | } 91 | return 0; 92 | } 93 | -------------------------------------------------------------------------------- /Section03/Thread pool/sec03_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 | } -------------------------------------------------------------------------------- /Section06/Code sample.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #define _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(addr) 3 | ANNOTATE_HAPPENS_BEFORE(addr) 4 | #define _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(addr) 5 | ANNOTATE_HAPPENS_AFTER(addr) 6 | -------------------------------------------------------------------------------- /Section06/Error types: -------------------------------------------------------------------------------- 1 | Invalid read of size 2 | at 0x: (location) 3 | by 0x: (location) 4 | by 0x: (location) 5 | Address 0x 6 | -------------------------------------------------------------------------------- /Section06/Fishy argument values log file: -------------------------------------------------------------------------------- 1 | ==32233== Argument 'size' of function malloc has a fishy (possibly 2 | negative) value: -3 3 | ==32233== at 0x4C2CFA7: malloc (vg_replace_malloc.c:298) 4 | ==32233== by 0x400555: foo (fishy.c:15) 5 | ==32233== by 0x400583: main (fishy.c:23) 6 | -------------------------------------------------------------------------------- /Section06/Makefile: -------------------------------------------------------------------------------- 1 | 2 | GCC := g++ 3 | 4 | OUTPUT := dispatcher_demo 5 | SOURCES := $(wildcard *.cpp) 6 | CCFLAGS := -pthread -std=c++11 -g3 7 | 8 | all: $(OUTPUT) 9 | 10 | $(OUTPUT): 11 | $(GCC) $(SOURCES) -o $(OUTPUT) $(CCFLAGS) 12 | 13 | clean: 14 | rm $(OUTPUT) 15 | 16 | .PHONY: all 17 | -------------------------------------------------------------------------------- /Section06/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 | -------------------------------------------------------------------------------- /Section06/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 | -------------------------------------------------------------------------------- /Section06/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 | -------------------------------------------------------------------------------- /Section06/dispatcher_demo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-Multithreading-with-Cplusplus/9b0e5a7beeceb4a7262666fa2465fdda0104c9db/Section06/dispatcher_demo -------------------------------------------------------------------------------- /Section06/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 | -------------------------------------------------------------------------------- /Section06/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 | -------------------------------------------------------------------------------- /Section06/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 | -------------------------------------------------------------------------------- /Section06/thread.cc: -------------------------------------------------------------------------------- 1 | // thread -*- C++ -*- 2 | 3 | // Copyright (C) 2008-2017 Free Software Foundation, Inc. 4 | // 5 | // This file is part of the GNU ISO C++ Library. This library is free 6 | // software; you can redistribute it and/or modify it under the 7 | // terms of the GNU General Public License as published by the 8 | // Free Software Foundation; either version 3, or (at your option) 9 | // any later version. 10 | 11 | // This library is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | 16 | // Under Section 7 of GPL version 3, you are granted additional 17 | // permissions described in the GCC Runtime Library Exception, version 18 | // 3.1, as published by the Free Software Foundation. 19 | 20 | // You should have received a copy of the GNU General Public License and 21 | // a copy of the GCC Runtime Library Exception along with this program; 22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 | // . 24 | 25 | 26 | #define _GLIBCXX_THREAD_ABI_COMPAT 1 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1) 33 | 34 | #if defined(_GLIBCXX_USE_GET_NPROCS) 35 | # include 36 | # define _GLIBCXX_NPROCS get_nprocs() 37 | #elif defined(_GLIBCXX_USE_PTHREADS_NUM_PROCESSORS_NP) 38 | # define _GLIBCXX_NPROCS pthread_num_processors_np() 39 | #elif defined(_GLIBCXX_USE_SYSCTL_HW_NCPU) 40 | # include 41 | # include 42 | static inline int get_nprocs() 43 | { 44 | int count; 45 | size_t size = sizeof(count); 46 | int mib[] = { CTL_HW, HW_NCPU }; 47 | if (!sysctl(mib, 2, &count, &size, NULL, 0)) 48 | return count; 49 | return 0; 50 | } 51 | # define _GLIBCXX_NPROCS get_nprocs() 52 | #elif defined(_GLIBCXX_USE_SC_NPROCESSORS_ONLN) 53 | # include 54 | # define _GLIBCXX_NPROCS sysconf(_SC_NPROCESSORS_ONLN) 55 | #elif defined(_GLIBCXX_USE_SC_NPROC_ONLN) 56 | # include 57 | # define _GLIBCXX_NPROCS sysconf(_SC_NPROC_ONLN) 58 | #else 59 | # define _GLIBCXX_NPROCS 0 60 | #endif 61 | 62 | #ifndef _GLIBCXX_USE_NANOSLEEP 63 | # ifdef _GLIBCXX_HAVE_SLEEP 64 | # include 65 | # elif defined(_GLIBCXX_HAVE_WIN32_SLEEP) 66 | # include 67 | # else 68 | # error "No sleep function known for this target" 69 | # endif 70 | #endif 71 | 72 | namespace std _GLIBCXX_VISIBILITY(default) 73 | { 74 | extern "C" 75 | { 76 | static void* execute_native_thread_routine(void* __p) 77 | { 78 | thread::_State_ptr __t{ static_cast(__p) }; 79 | __t->_M_run(); 80 | return nullptr; 81 | } 82 | 83 | #if _GLIBCXX_THREAD_ABI_COMPAT 84 | static void* 85 | execute_native_thread_routine_compat(void* __p) 86 | { 87 | thread::_Impl_base* __t = static_cast(__p); 88 | thread::__shared_base_type __local; 89 | // Now that a new thread has been created we can transfer ownership of 90 | // the thread state to a local object, breaking the reference cycle 91 | // created in thread::_M_start_thread. 92 | __local.swap(__t->_M_this_ptr); 93 | __t->_M_run(); 94 | return nullptr; 95 | } 96 | #endif 97 | } // extern "C" 98 | 99 | _GLIBCXX_BEGIN_NAMESPACE_VERSION 100 | 101 | thread::_State::~_State() = default; 102 | 103 | void 104 | thread::join() 105 | { 106 | int __e = EINVAL; 107 | 108 | if (_M_id != id()) 109 | __e = __gthread_join(_M_id._M_thread, 0); 110 | 111 | if (__e) 112 | __throw_system_error(__e); 113 | 114 | _M_id = id(); 115 | } 116 | 117 | void 118 | thread::detach() 119 | { 120 | int __e = EINVAL; 121 | 122 | if (_M_id != id()) 123 | __e = __gthread_detach(_M_id._M_thread); 124 | 125 | if (__e) 126 | __throw_system_error(__e); 127 | 128 | _M_id = id(); 129 | } 130 | 131 | void thread::_M_start_thread(_State_ptr state, void (*)()) 132 | { 133 | const int err = __gthread_create(&_M_id._M_thread, 134 | &execute_native_thread_routine, 135 | state.get()); 136 | if (err) 137 | __throw_system_error(err); 138 | state.release(); 139 | } 140 | 141 | #if _GLIBCXX_THREAD_ABI_COMPAT 142 | void 143 | thread::_M_start_thread(__shared_base_type __b) 144 | { 145 | if (!__gthread_active_p()) 146 | #if __cpp_exceptions 147 | throw system_error(make_error_code(errc::operation_not_permitted), 148 | "Enable multithreading to use std::thread"); 149 | #else 150 | __throw_system_error(int(errc::operation_not_permitted)); 151 | #endif 152 | 153 | _M_start_thread(std::move(__b), nullptr); 154 | } 155 | 156 | void 157 | thread::_M_start_thread(__shared_base_type __b, void (*)()) 158 | { 159 | auto ptr = __b.get(); 160 | // Create a reference cycle that will be broken in the new thread. 161 | ptr->_M_this_ptr = std::move(__b); 162 | int __e = __gthread_create(&_M_id._M_thread, 163 | &execute_native_thread_routine_compat, ptr); 164 | if (__e) 165 | { 166 | ptr->_M_this_ptr.reset(); // break reference cycle, destroying *ptr. 167 | __throw_system_error(__e); 168 | } 169 | } 170 | #endif 171 | 172 | unsigned int 173 | thread::hardware_concurrency() noexcept 174 | { 175 | int __n = _GLIBCXX_NPROCS; 176 | if (__n < 0) 177 | __n = 0; 178 | return __n; 179 | } 180 | 181 | namespace this_thread 182 | { 183 | void 184 | __sleep_for(chrono::seconds __s, chrono::nanoseconds __ns) 185 | { 186 | #ifdef _GLIBCXX_USE_NANOSLEEP 187 | __gthread_time_t __ts = 188 | { 189 | static_cast(__s.count()), 190 | static_cast(__ns.count()) 191 | }; 192 | while (::nanosleep(&__ts, &__ts) == -1 && errno == EINTR) 193 | { } 194 | #elif defined(_GLIBCXX_HAVE_SLEEP) 195 | # ifdef _GLIBCXX_HAVE_USLEEP 196 | ::sleep(__s.count()); 197 | if (__ns.count() > 0) 198 | { 199 | long __us = __ns.count() / 1000; 200 | if (__us == 0) 201 | __us = 1; 202 | ::usleep(__us); 203 | } 204 | # else 205 | ::sleep(__s.count() + (__ns.count() >= 1000000)); 206 | # endif 207 | #elif defined(_GLIBCXX_HAVE_WIN32_SLEEP) 208 | unsigned long ms = __ns.count() / 1000000; 209 | if (__ns.count() > 0 && ms == 0) 210 | ms = 1; 211 | ::Sleep(chrono::milliseconds(__s).count() + ms); 212 | #endif 213 | } 214 | } 215 | 216 | _GLIBCXX_END_NAMESPACE_VERSION 217 | } // namespace std 218 | 219 | #endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1 220 | -------------------------------------------------------------------------------- /Section06/unsyscall/Makefile: -------------------------------------------------------------------------------- 1 | 2 | GCC := g++ 3 | 4 | OUTPUT := unsyscall 5 | SOURCES := $(wildcard *.cpp) 6 | CCFLAGS := -pthread -std=c++11 -g3 7 | 8 | all: $(OUTPUT) 9 | 10 | $(OUTPUT): 11 | $(GCC) $(SOURCES) -o $(OUTPUT) $(CCFLAGS) 12 | 13 | clean: 14 | rm $(OUTPUT) 15 | 16 | .PHONY: all 17 | -------------------------------------------------------------------------------- /Section06/unsyscall/unsyscall: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-Multithreading-with-Cplusplus/9b0e5a7beeceb4a7262666fa2465fdda0104c9db/Section06/unsyscall/unsyscall -------------------------------------------------------------------------------- /Section06/unsyscall/unsyscall.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | char* arr = (char*) malloc(10); 6 | int* arr2 = (int*) malloc(sizeof(int)); 7 | write(1, arr, 10 ); 8 | exit(arr2[0]); 9 | } 10 | -------------------------------------------------------------------------------- /Section06/unval.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | int main() { 4 | int x; 5 | printf ("x = %d\n", x); 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /Section06/unval/Makefile: -------------------------------------------------------------------------------- 1 | 2 | GCC := g++ 3 | 4 | OUTPUT := unval 5 | SOURCES := $(wildcard *.cpp) 6 | CCFLAGS := -pthread -std=c++11 -g3 7 | 8 | all: $(OUTPUT) 9 | 10 | $(OUTPUT): 11 | $(GCC) $(SOURCES) -o $(OUTPUT) $(CCFLAGS) 12 | 13 | clean: 14 | rm $(OUTPUT) 15 | 16 | .PHONY: all 17 | -------------------------------------------------------------------------------- /Section06/unval/unval: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-Multithreading-with-Cplusplus/9b0e5a7beeceb4a7262666fa2465fdda0104c9db/Section06/unval/unval -------------------------------------------------------------------------------- /Section06/unval/unval.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | int x; 6 | printf ("x = %d\n", x); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /Section06/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 | -------------------------------------------------------------------------------- /Section06/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 | -------------------------------------------------------------------------------- /Section07/Code Example.cpp: -------------------------------------------------------------------------------- 1 | bool TAS(bool lock) { 2 | if (lock) { 3 | return true; 4 | } 5 | else { 6 | lock = true; 7 | return false; 8 | } 9 | } 10 | 11 | bool CAS(int* p, int old, int new) { 12 | if (*p != old) { 13 | return false; 14 | } 15 | *p = new; 16 | return true; 17 | } 18 | 19 | volatile bool lock = false; 20 | void critical() { 21 | while (TAS(&lock) == false); 22 | // Critical section 23 | lock = 0; 24 | } 25 | -------------------------------------------------------------------------------- /Section07/Code Example2.cpp: -------------------------------------------------------------------------------- 1 | class Foo { 2 | static std::map strings; 3 | static std::string oneString; 4 | public: 5 | static void init(int a, std::string b, std::string c) { 6 | strings.insert(std::pair(a, b)); 7 | oneString = c; 8 | } 9 | }; 10 | std::map Foo::strings; 11 | std::string Foo::oneString; 12 | 13 | class Bar { 14 | static std::string name; 15 | static std::string initName(); 16 | public: 17 | void init(); 18 | }; 19 | // Static initializations. 20 | std::string Bar::name = Bar::initName(); 21 | 22 | std::string Bar::initName() { 23 | Foo::init(1, "A", "B"); 24 | return "Bar"; 25 | } 26 | 27 | class Foo { 28 | static std::map& strings(); 29 | static std::string oneString; 30 | public: 31 | static void init(int a, std::string b, std::string c) { 32 | static std::map stringsStatic = Foo::strings(); 33 | stringsStatic.insert(std::pair(a, b)); 34 | oneString = c; 35 | } 36 | }; 37 | std::string Foo::oneString; 38 | 39 | std::map& Foo::strings() { 40 | static std::map* stringsStatic = new std::map(); 42 | return *stringsStatic; 43 | } 44 | -------------------------------------------------------------------------------- /Section07/dispatcher.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | dispatcher.cpp - Implementation of the Dispatcher class. 3 | */ 4 | 5 | #include "dispatcher.h" 6 | #include 7 | using namespace std; 8 | 9 | queue Dispatcher::requests; 10 | queue Dispatcher::workers; 11 | mutex Dispatcher::requestsMutex; 12 | mutex Dispatcher::workersMutex; 13 | vector Dispatcher::allWorkers; 14 | vector Dispatcher::threads; 15 | // --- INIT --- 16 | bool Dispatcher::init(int workers) { 17 | thread* t = 0; 18 | Worker* w = 0; 19 | for (int i = 0; i < workers; ++i) { 20 | w = new Worker; 21 | allWorkers.push_back(w); 22 | t = new thread(&Worker::run, w); 23 | threads.push_back(t); 24 | } 25 | return true; 26 | } 27 | // --- STOP --- 28 | bool Dispatcher::stop() { 29 | for (int i = 0; i < allWorkers.size(); ++i) { 30 | allWorkers[i]->stop(); 31 | } 32 | cout << "Stopped workers.\n"; 33 | for (int j = 0; j < threads.size(); ++j) { 34 | threads[j]->join(); 35 | cout << "Joined threads.\n"; 36 | } 37 | 38 | return true; 39 | } 40 | 41 | // --- ADD REQUEST --- 42 | void Dispatcher::addRequest(AbstractRequest* request) { 43 | workersMutex.lock(); 44 | if (!workers.empty()) { 45 | Worker* worker = workers.front(); 46 | worker->setRequest(request); 47 | condition_variable* cv; 48 | worker->getCondition(cv); 49 | cv->notify_one(); 50 | workers.pop(); 51 | workersMutex.unlock(); 52 | } 53 | else { 54 | workersMutex.unlock(); 55 | requestsMutex.lock(); 56 | requests.push(request); 57 | requestsMutex.unlock(); 58 | } 59 | 60 | } 61 | 62 | 63 | // --- ADD WORKER --- 64 | bool Dispatcher::addWorker(Worker* worker) { 65 | 66 | bool wait = true; 67 | requestsMutex.lock(); 68 | if (!requests.empty()) { 69 | AbstractRequest* request = requests.front(); 70 | worker->setRequest(request); 71 | requests.pop(); 72 | wait = false; 73 | requestsMutex.unlock(); 74 | } 75 | else { 76 | requestsMutex.unlock(); 77 | workersMutex.lock(); 78 | workers.push(worker); 79 | workersMutex.unlock(); 80 | } 81 | return wait; 82 | } 83 | -------------------------------------------------------------------------------- /Section07/worker.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | worker.cpp - Implementation of the Worker class. 3 | */ 4 | 5 | #include "worker.h" 6 | #include "dispatcher.h" 7 | #include 8 | 9 | using namespace std; 10 | 11 | void Worker::getCondition(condition_variable* &cv) { 12 | cv = &(this)->cv; 13 | } 14 | 15 | void Worker::run() { 16 | while (running) { 17 | if (ready) { 18 | // Execute the request. 19 | ready = false; 20 | request->process(); 21 | request->finish(); 22 | } 23 | 24 | if (Dispatcher::addWorker(this)) { 25 | // Use the ready loop to deal with spurious wake-ups. 26 | while (!ready && running) { 27 | if (cv.wait_for(ulock, chrono::seconds(1)) == cv_status::timeout) { 28 | // We timed out, but we keep waiting unless the worker is 29 | // stopped by the dispatcher. 30 | } 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Section07/worker.h: -------------------------------------------------------------------------------- 1 | /* 2 | worker.h - Header file for the Worker class. 3 | */ 4 | 5 | #pragma once 6 | #ifndef WORKER_H 7 | #define WORKER_H 8 | 9 | #include "abstract_request.h" 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | class Worker { 16 | condition_variable cv; 17 | mutex mtx; 18 | unique_lock ulock; 19 | AbstractRequest* request; 20 | bool running; 21 | bool ready; 22 | 23 | public: 24 | Worker() { running = true; ready = false; ulock = unique_lock(mtx); } 25 | void run(); 26 | void stop() { running = false; } 27 | void setRequest(AbstractRequest* request) { this->request = request; ready = true; } 28 | void getCondition(condition_variable* &cv); 29 | }; 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /Section08/Code Example 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 | -------------------------------------------------------------------------------- /Section08/Code Example 1/code1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-Multithreading-with-Cplusplus/9b0e5a7beeceb4a7262666fa2465fdda0104c9db/Section08/Code Example 1/code1 -------------------------------------------------------------------------------- /Section08/Code Example 1/code1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | std::atomic count; 6 | void worker() { 7 | count.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:" << count << '\n'; 24 | } 25 | -------------------------------------------------------------------------------- /Section08/Code Example 2/Makefile: -------------------------------------------------------------------------------- 1 | 2 | GCC := g++ 3 | 4 | OUTPUT := code2 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 | -------------------------------------------------------------------------------- /Section08/Code Example 2/code2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-Multithreading-with-Cplusplus/9b0e5a7beeceb4a7262666fa2465fdda0104c9db/Section08/Code Example 2/code2 -------------------------------------------------------------------------------- /Section08/Code Example 2/code2.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 | int main() { 26 | std::iota(data.begin(), data.end(), 1); 27 | cnt = data.size() - 1; 28 | std::vector v; 29 | for (int n = 0; n < 10; ++n) { 30 | v.emplace_back(reader, n); 31 | } 32 | for (std::thread& t : v) { 33 | t.join(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Section08/__atomic built-in methods.cpp: -------------------------------------------------------------------------------- 1 | type __atomic_load_n (type *ptr, int memorder) 2 | void __atomic_load (type *ptr, type *ret, int memorder) 3 | void __atomic_store_n (type *ptr, type val, int memorder) 4 | void __atomic_store (type *ptr, type *val, int memorder) 5 | type __atomic_exchange_n (type *ptr, type val, int memorder) 6 | void __atomic_exchange (type *ptr, type *val, type *ret, int memorder) 7 | bool __atomic_compare_exchange_n (type *ptr, type *expected, type desired, 8 | bool weak, int success_memorder, int failure_memorder) 9 | bool __atomic_compare_exchange (type *ptr, type *expected, type *desired, 10 | bool weak, int success_memorder, int failure_memorder) 11 | 12 | type __atomic_add_fetch (type *ptr, type val, int memorder) 13 | type __atomic_sub_fetch (type *ptr, type val, int memorder) 14 | type __atomic_and_fetch (type *ptr, type val, int memorder) 15 | type __atomic_xor_fetch (type *ptr, type val, int memorder) 16 | type __atomic_or_fetch (type *ptr, type val, int memorder) 17 | type __atomic_nand_fetch (type *ptr, type val, int memorder) 18 | 19 | type __atomic_fetch_add (type *ptr, type val, int memorder) 20 | type __atomic_fetch_sub (type *ptr, type val, int memorder) 21 | type __atomic_fetch_and (type *ptr, type val, int memorder) 22 | type __atomic_fetch_xor (type *ptr, type val, int memorder) 23 | type __atomic_fetch_or (type *ptr, type val, int memorder) 24 | type __atomic_fetch_nand (type *ptr, type val, int memorder) 25 | 26 | bool __atomic_test_and_set (void *ptr, int memorder) 27 | 28 | void __atomic_clear (bool *ptr, int memorder) 29 | 30 | void __atomic_thread_fence (int memorder) 31 | 32 | void __atomic_signal_fence (int memorder) 33 | 34 | bool __atomic_always_lock_free (size_t size, void *ptr) 35 | 36 | bool __atomic_is_lock_free (size_t size, void *ptr) 37 | -------------------------------------------------------------------------------- /Section08/__sync-prefixed extension.cpp: -------------------------------------------------------------------------------- 1 | type __sync_fetch_and_add (type *ptr, type value, ...) 2 | type __sync_fetch_and_sub (type *ptr, type value, ...) 3 | type __sync_fetch_and_or (type *ptr, type value, ...) 4 | type __sync_fetch_and_and (type *ptr, type value, ...) 5 | type __sync_fetch_and_xor (type *ptr, type value, ...) 6 | type __sync_fetch_and_nand (type *ptr, type value, ...) 7 | 8 | type __sync_add_and_fetch (type *ptr, type value, ...) 9 | type __sync_sub_and_fetch (type *ptr, type value, ...) 10 | type __sync_or_and_fetch (type *ptr, type value, ...) 11 | type __sync_and_and_fetch (type *ptr, type value, ...) 12 | type __sync_xor_and_fetch (type *ptr, type value, ...) 13 | type __sync_nand_and_fetch (type *ptr, type value, ...) 14 | 15 | bool __sync_bool_compare_and_swap (type *ptr, type oldval, type newval, 16 | ...) 17 | type __sync_val_compare_and_swap (type *ptr, type oldval, type newval, ...) 18 | 19 | __sync_synchronize (...) 20 | 21 | type __sync_lock_test_and_set (type *ptr, type value, ...) 22 | 23 | void __sync_lock_release (type *ptr, ...) 24 | -------------------------------------------------------------------------------- /Section08/memory order.cpp: -------------------------------------------------------------------------------- 1 | enum memory_order { 2 | memory_order_relaxed, 3 | memory_order_consume, 4 | memory_order_acquire, 5 | memory_order_release, 6 | memory_order_acq_rel, 7 | memory_order_seq_cst 8 | }; 9 | -------------------------------------------------------------------------------- /Section09/Code_Example1.c: -------------------------------------------------------------------------------- 1 | int MPI_Send( 2 | void* data, 3 | int count, 4 | MPI_Datatype datatype, 5 | int destination, 6 | int tag, 7 | MPI_Comm communicator) 8 | 9 | int MPI_Recv( 10 | void* data, 11 | int count, 12 | MPI_Datatype datatype, 13 | int source, 14 | int tag, 15 | MPI_Comm communicator, 16 | MPI_Status* status) 17 | -------------------------------------------------------------------------------- /Section09/Code_Example2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | struct car { 7 | int shifts; 8 | int topSpeed; 9 | }; 10 | 11 | int main(int argc, char **argv) { 12 | const int tag = 13; 13 | int size, rank; 14 | MPI_Init(&argc, &argv); 15 | 16 | MPI_Comm_size(MPI_COMM_WORLD, &size); 17 | 18 | if (size < 2) { 19 | fprintf(stderr,"Requires at least two processes.\n"); 20 | MPI_Abort(MPI_COMM_WORLD, 1); 21 | } 22 | 23 | const int nitems = 2; 24 | int blocklengths[2] = {1,1}; 25 | MPI_Datatype types[2] = {MPI_INT, MPI_INT}; 26 | MPI_Datatype mpi_car_type; 27 | MPI_Aint offsets[2]; 28 | 29 | offsets[0] = offsetof(car, shifts); 30 | offsets[1] = offsetof(car, topSpeed); 31 | 32 | MPI_Type_create_struct(nitems, blocklengths, offsets, types, 33 | &mpi_car_type); 34 | MPI_Type_commit(&mpi_car_type); 35 | 36 | MPI_Comm_rank(MPI_COMM_WORLD, &rank); 37 | if (rank == 0) { 38 | car send; 39 | send.shifts = 4; 40 | send.topSpeed = 100; 41 | 42 | const int dest = 1; 43 | MPI_Send(&send, 1, mpi_car_type, dest, tag, MPI_COMM_WORLD); 44 | 45 | printf("Rank %d: sent structure car\n", rank); 46 | } 47 | if (rank == 1) { 48 | MPI_Status status; 49 | const int src = 0; 50 | 51 | car recv; 52 | 53 | MPI_Recv(&recv, 1, mpi_car_type, src, tag, MPI_COMM_WORLD, 54 | &status); 55 | printf("Rank %d: Received: shifts = %d topSpeed = %d\n", rank, 56 | recv.shifts, recv.topSpeed); 57 | } 58 | 59 | MPI_Type_free(&mpi_car_type); 60 | MPI_Finalize(); 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /Section09/Code_Example3.c: -------------------------------------------------------------------------------- 1 | int MPI_Bcast( 2 | void *buffer, 3 | int count, 4 | MPI_Datatype datatype, 5 | int root, 6 | MPI_Comm comm) 7 | 8 | int MPI_Scatter( 9 | void* send_data, 10 | int send_count, 11 | MPI_Datatype send_datatype, 12 | void* recv_data, 13 | int recv_count, 14 | MPI_Datatype recv_datatype, 15 | int root, 16 | MPI_Comm communicator) 17 | 18 | int MPI_Gather( 19 | void* send_data, 20 | int send_count, 21 | MPI_Datatype send_datatype, 22 | void* recv_data, 23 | int recv_count, 24 | MPI_Datatype recv_datatype, 25 | int root, 26 | MPI_Comm communicator) 27 | 28 | 29 | -------------------------------------------------------------------------------- /Section09/MPI_Type_create_struct.c: -------------------------------------------------------------------------------- 1 | int MPI_Type_create_struct( 2 | int count, 3 | int array_of_blocklengths[], 4 | const MPI_Aint array_of_displacements[], 5 | const MPI_Datatype array_of_types[], 6 | MPI_Datatype *newtype) 7 | 8 | -------------------------------------------------------------------------------- /Section09/mpi_hello_world/mpi_hello_world: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-Multithreading-with-Cplusplus/9b0e5a7beeceb4a7262666fa2465fdda0104c9db/Section09/mpi_hello_world/mpi_hello_world -------------------------------------------------------------------------------- /Section09/mpi_hello_world/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 | -------------------------------------------------------------------------------- /Section09/omp_hello.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * FILE: omp_hello.c 3 | * DESCRIPTION: 4 | * OpenMP Example - Hello World - C/C++ Version 5 | * In this simple example, the master thread forks a parallel region. 6 | * All threads in the team obtain their unique thread number and print it. 7 | * The master thread only prints the total number of threads. Two OpenMP 8 | * library routines are used to obtain the number of threads and each 9 | * thread's number. 10 | * AUTHOR: Blaise Barney 5/99 11 | * LAST REVISED: 04/06/05 12 | ******************************************************************************/ 13 | #include 14 | #include 15 | #include 16 | 17 | int main (int argc, char *argv[]) 18 | { 19 | int nthreads, tid; 20 | 21 | #pragma omp parallel private(nthreads, tid) 22 | { 23 | tid = omp_get_thread_num(); 24 | printf("Hello World from thread = %d\n", tid); 25 | 26 | if (tid == 0) 27 | { 28 | nthreads = omp_get_num_threads(); 29 | printf("Number of threads = %d\n", nthreads); 30 | } 31 | } /* All threads join master thread and disband */ 32 | } 33 | -------------------------------------------------------------------------------- /Section09/send_recv.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char** argv) { 6 | MPI_Init(NULL, NULL); 7 | int world_rank; 8 | MPI_Comm_rank(MPI_COMM_WORLD, &world_rank); 9 | int world_size; 10 | MPI_Comm_size(MPI_COMM_WORLD, &world_size); 11 | 12 | if (world_size < 2) { 13 | fprintf(stderr, "World size must be greater than 1 for %s\n", argv[0]); 14 | MPI_Abort(MPI_COMM_WORLD, 1); 15 | } 16 | 17 | int number; 18 | if (world_rank == 0) { 19 | number = -1; 20 | MPI_Send(&number, 1, MPI_INT, 1, 0, MPI_COMM_WORLD); 21 | } 22 | else if (world_rank == 1) { 23 | MPI_Recv(&number, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); 24 | printf("Process 1 received number %d from process 0\n", number); 25 | } 26 | MPI_Finalize(); 27 | } 28 | -------------------------------------------------------------------------------- /Section09/send_recv_demo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-Multithreading-with-Cplusplus/9b0e5a7beeceb4a7262666fa2465fdda0104c9db/Section09/send_recv_demo -------------------------------------------------------------------------------- /mpi/hello_mpi_world: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-Multithreading-with-Cplusplus/9b0e5a7beeceb4a7262666fa2465fdda0104c9db/mpi/hello_mpi_world -------------------------------------------------------------------------------- /mpi/hello_mpi_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 | -------------------------------------------------------------------------------- /mpi/hellohybrid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mastering-Multithreading-with-Cplusplus/9b0e5a7beeceb4a7262666fa2465fdda0104c9db/mpi/hellohybrid -------------------------------------------------------------------------------- /mpi/hellohybrid.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "mpi.h" 3 | #include 4 | 5 | int main(int argc, char *argv[]) { 6 | int numprocs, rank, namelen; 7 | char processor_name[MPI_MAX_PROCESSOR_NAME]; 8 | int iam = 0, np = 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(processor_name, &namelen); 14 | 15 | #pragma omp parallel default(shared) private(iam, np) 16 | { 17 | np = omp_get_num_threads(); 18 | iam = omp_get_thread_num(); 19 | printf("Hello from thread %d out of %d from process %d out of %d on %s\n", 20 | iam, np, rank, numprocs, processor_name); 21 | } 22 | 23 | MPI_Finalize(); 24 | } 25 | -------------------------------------------------------------------------------- /mpi/my_hostfile: -------------------------------------------------------------------------------- 1 | 2 | node1 3 | node2 4 | --------------------------------------------------------------------------------