From the course: Complete Guide to Parallel and Concurrent Programming with C++

Thread versus process: C++ demo

- [Instructor] Now, before we demonstrate a process with multiple threads in action, let's first take a look at the number of processors that are available on this computer, which we'll be using for demonstrations throughout this course. To do that, I'll press Ctrl + Shift + Esc, which opens the Task Manager, and then go to the Performance tab. Down at the bottom, we can see that this computer has two cores and four logical processors. Those numbers mean that this computer has two separate and complete physical processing cores, and each of those cores supports something called hyperthreading, which enables them to each run two independent threads at the same time. So the computer treats those two physical cores as four logical processors. Now, the hyperthreading in those two cores does not mean I'll get double the performance out of each of them. Hyperthreading takes advantage of unused parts of the processor, so if one thread is paused or not using a specific resource, then the other thread may be able to use it. Under certain workloads, that can create performance improvements, but it's highly application dependent. The moving blue graph shows the total percentage of CPU utilization for all of those processors. I don't have much running right now, so the usage stays low, down near just a few percent. If I want to see the CPU usage for each of those processors individually, I can get more information by clicking the Open Resource Monitor link and then selecting the CPU tab. The charts on the right show the total CPU usage on top, and if I scroll down, I can see how much each of the individual processors on this computer are being utilized. The table on the left lists all of the current processes running on this computer with information including each processor's unique process ID number, it's PID, its current status, the number of threads, and its average CPU usage. Now, to show you a few threads running in a process, we've created this short example program, which you can find in the Exercise Files Chapter02 02_02 begin directory. This program defines a simple function on line 9 called cpu_waster, which can be used to create a new thread that spins in a while loop forever. It prints the process ID on line 10 using the getpid function, which is declared in the unistd header. And then on line 11, it uses the get_id function to print the current thread ID. After that, the cpu_waster enters into an infinite while loop. It's not doing anything useful, but the thread will stay alive forever and continuously use CPU cycles. Down in this program's main function, lines 16 and 17 print messages with the process ID and main thread's ID value. Then after that, the program instantiates two new threads. To create threads throughout this course, we'll be using the C++ Standard Libraries Thread class, which is defined in the thread header file. How threads are actually compiled and implemented under the hood can vary between operating systems, but by writing our code using the standard library classes, it should be portable to different development environments. The two new thread objects created on lines 18 and 19 named thread 1 and thread 2 are assigned the cpu_waster as their top level function to execute. After those two threads start, the main thread enters into its own infinite while loop on line 21 to keep the process alive. Now I'll switch over to a Command Prompt, open to a folder with the example code, and I'll use the make command to build the program. It warns me that the data type used to represent a thread ID may not be compatible with the printf function because it's not actually an integer data type, but for the sake of this demonstration, that's okay. The printf function will do its best to display the thread ID as a numeric value, which will be enough to at least see that the three threads in this program are different. Now, I'll run the executable, thread_process_demo.exe. I can see that the operating system assigned this program, the process ID number 232, and the main thread has an ID value represented by this number, 98368. The two cpu_waster threads that were created have the same process ID as the main thread, but they each have their own unique thread IDs. Switching over to the Task Manager, I can see that the overall CPU usage has jumped to over 50%. That's because the two cpu_waster threads I created are running continuously and using CPU resources on half of the four logical processors on this computer. Looking at the Resource Monitor's CPU tab, I can see how that workload is being distributed across all of those processors. If I scroll down in the Processes window, I see a process called thread_process_demo.exe. Now, you may have noticed that it has a different process ID number than our program displayed earlier, and that's because we're using Cygwin to emulate a POSIX-compatible environment on our Windows computer. The process ID shown here in the Windows Resource Monitor is the ID that Windows assigned to the process, whereas the value the program printed out was the process ID it got from the Cygwin emulation environment. This program will continue running forever if I don't stop it, so I'll manually terminate it by closing the Command Prompt window that was running the program. If I look at the CPU usage now, I can see that when I closed the program, those cpu_wasting threads were terminated too, and the CPU usage dropped back down to just a few percent.

Contents