In this part of my C++ Tutorial I’ll be focusing on Threads. We’ll cover how to create, pause, and pool threads. We will then compare how long it takes to generate a list of prime numbers with and without threads. Also we’ll check out many ways of working with time.
Like always the heavily commented code follows the video below. Feel free to do whatever you’d like with it.
If you like videos like this, consider donating $1, or simply turn off Ad Blocking software. Either helps me to continue making free educational video tutorials.
Code from the Video
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
// ---------- C++ TUTORIAL 16 ---------- #include <cstdlib> #include <iostream> #include <string> #include <vector> #include <ctime> #include <numeric> #include <cmath> #include <sstream> #include <thread> #include <chrono> #include <ctime> #include <mutex> int GetRandom(int max){ srand(time(NULL)); return rand() % max; } /* ----- SIMPLE THREAD EXAMPLE ----- void ExecuteThread(int id){ // Get current time auto nowTime = std::chrono::system_clock::now(); // Convert to a time we can output std::time_t sleepTime = std::chrono::system_clock::to_time_t(nowTime); // Convert to current time zone tm myLocalTime = *localtime(&sleepTime); // Print full time information std::cout << "Thread " << id << " Sleep Time : " << std::ctime(&sleepTime) << "\n"; // Get separate pieces std::cout << "Month : " << myLocalTime.tm_mon << "\n"; std::cout << "Day : " << myLocalTime.tm_mday << "\n"; std::cout << "Year : " << myLocalTime.tm_year + 1900 << "\n"; std::cout << "Hours : " << myLocalTime.tm_hour << "\n"; std::cout << "Minutes : " << myLocalTime.tm_min << "\n"; std::cout << "Seconds : " << myLocalTime.tm_sec << "\n\n"; // Put the thread to sleep for up to 3 seconds std::this_thread::sleep_for (std::chrono::seconds(GetRandom(3))); nowTime = std::chrono::system_clock::now(); sleepTime = std::chrono::system_clock::to_time_t(nowTime); std::cout << "Thread " << id << " Awake Time : " << std::ctime(&sleepTime) << "\n"; } ----- END SIMPLE THREAD EXAMPLE ----- */ std::string GetTime(){ auto nowTime = std::chrono::system_clock::now(); std::time_t sleepTime = std::chrono::system_clock::to_time_t(nowTime); return std::ctime(&sleepTime); } double acctBalance = 100; // Protects shared data from being accessed at the // same time std::mutex acctLock; void GetMoney(int id, double withdrawal){ // The exception safe way to protect access // to code within its scope. The lock is released // after execution leaves this scope std::lock_guard<std::mutex> lock(acctLock); // Blocks access between lock and unlock // until execution completes // This isn't good to use however if an error // occurs between lock and unlock // acctLock.lock(); std::this_thread::sleep_for(std::chrono::seconds(3)); std::cout << id << " tries to withdrawal $" << withdrawal << " on " << GetTime() << "\n"; if((acctBalance - withdrawal) >= 0){ acctBalance -= withdrawal; std::cout << "New Account Balance is $" << acctBalance << "\n"; } else { std::cout << "Not Enough Money in Account\n"; std::cout << "Current Balance is $" << acctBalance << "\n"; } // acctLock.unlock(); } int main() { /* ----- SIMPLE THREAD EXAMPLE ----- // Create a thread and pass a parameter // to the function std::thread th1 (ExecuteThread, 1); // Join the thread to the main thread // meaning main waits for this thread to // stop executing before continuing execution // of code in main th1.join(); std::thread th2 (ExecuteThread, 2); th2.join(); ----- END SIMPLE THREAD EXAMPLE ----- */ // We will create a pool of threads that // will access a bank account in no particular // order std::thread threads[10]; for(int i = 0; i < 10; ++i){ threads[i] = std::thread(GetMoney, i, 15); } for(int i = 0; i < 10; ++i){ threads[i].join(); } return 0; } // ---------- CALCULATE PRIMES WITHOUT THREADS ----------- void FindPrimes(unsigned int start, unsigned int end, std::vector<unsigned int>& vect){ // Cycle through numbers while ignoring evens for(unsigned int x = start; x <= end; x += 2){ for(unsigned int y = 2; y < x; y++){ if((x % y) == 0){ break; } else if((y + 1) == x){ vect.push_back(x); } } } } int main() { std::vector<unsigned int> primeVect; // Get time before code starts executing int startTime = clock(); FindPrimes(1, 100000, primeVect); for(auto i: primeVect) std::cout << i << "\n"; // Get time after execution int endTime = clock(); // Print out the number of seconds by taking the difference // and dividing by the clock ticks per second std::cout << "Execution Time : " << (endTime - startTime)/double(CLOCKS_PER_SEC) << std::endl; return 0; } // ---------- END CALCULATE PRIMES WITHOUT THREADS ----------- // ---------- CALCULATE PRIMES WITH THREADS ----------- // Used to protect writing to the vector std::mutex vectLock; std::vector<unsigned int> primeVect; void FindPrimes(unsigned int start, unsigned int end){ // Cycle through numbers while ignoring evens for(unsigned int x = start; x <= end; x += 2){ // If a modulus is 0 we know it isn't prime for(unsigned int y = 2; y < x; y++){ if((x % y) == 0){ break; } else if((y + 1) == x){ vectLock.lock(); primeVect.push_back(x); vectLock.unlock(); } } } } void FindPrimesWithThreads(unsigned int start, unsigned int end, unsigned int numThreads){ std::vector<std::thread> threadVect; // Divide up the calculation so each thread // operates on different primes unsigned int threadSpread = end / numThreads; unsigned int newEnd = start + threadSpread - 1; // Create prime list for each thread for(unsigned int x = 0; x < numThreads; x++){ threadVect.emplace_back(FindPrimes, start, newEnd); start += threadSpread; newEnd += threadSpread; } for(auto& t : threadVect){ t.join(); } } int main() { // Get time before code starts executing int startTime = clock(); FindPrimesWithThreads(1, 100000, 3); // Get time after execution int endTime = clock(); for(auto i: primeVect) std::cout << i << "\n"; // Print out the number of seconds std::cout << "Execution Time : " << (endTime - startTime)/double(CLOCKS_PER_SEC) << std::endl; return 0; } // ---------- END CALCULATE PRIMES WITH THREADS ----------- // ---------- END C++ TUTORIAL 16 ---------- |
Leave a Reply