Free since 2005 · No login required
AT

Academic Tutorials

Learn at your own pace

site-mobile-top-banner · 320x50

Multithreading in C++

Added 31 Jul 2008

Multithreading is growing in importance in modern programming for a variety of reasons, not the least of which being that Windows supports multithreading. While C++ does not feature built-in support for multithreading, it can be used to created multithreaded programs, which is the subject of this article. It is taken from chapter three of The Art of C++, written by Herbert Schildt (McGraw-Hill/Osborne, 2004; ISBN: 0072255129).

Multithreading is becoming an increasingly important part of modern programming. One reason for this is that multithreading enables a program to make the best use of available CPU cycles, thus allowing very efficient programs to be written. Another reason is that multithreading is a natural choice for handling event-driven code, which is so common in today’s highly distributed, networked, GUI-based environments. Of course, the fact that the most widely used operating system, Windows, supports multithreading is also a factor. Whatever the reasons, the increased use of multithreading is changing the way that programmers think about the fundamental architecture of a program. Although C++ does not contain built-in support for multithreaded programs, it is right at home in this arena.

Because of its growing importance, this chapter explores using C++ to create multithreaded programs. It does so by developing two multithreaded applications. The first is a thread control panel, which you can use to control the execution of threads within a program. This is both an interesting demonstration of multithreading and a practical tool that you can use when developing multithreaded applications. The second example shows how to apply multithreading to a practical example by creating a modified version of the garbage collector from Chapter 2 that runs in a background thread.

This chapter also serves another purpose: it shows how adept C++ is at interfacing directly to the operating system. In some other languages, such as Java, there is a layer of processing between your program and the OS. This layer adds overhead that can be unacceptable for some types of programs, such as those used in a real-time environment. In sharp contrast, C++ has direct access to low-level functionality provided by the operating system. This is one of the reasons C++ can produce higher performance code.

What Is Multithreading?

Before beginning, it is necessary to define precisely what is meant by the term multithreading. Multithreading is a specialized form of multitasking. In general, there are two types of multitasking: process-based and thread-based. A process is, in essence, a program that is executing. Thus, process-based multitasking is the feature that allows your computer to run two or more programs concurrently. For example, it is process-based multitasking that allows you to run a word processor at the same time you are using a spreadsheet or browsing the Internet. In process-based multitasking, a program is the smallest unit of code that can be dispatched by the scheduler.

A thread is a dispatchable unit of executable code. The name comes from the concept of a “thread of execution.” In a thread-based multitasking environment, all processes have at least one thread, but they can have more. This means that a single program can perform two or more tasks concurrently. For instance, a text editor can be formatting text at the same time that it is printing, as long as these two actions are being performed by two separate threads. The differences between process-based and thread-based multitasking can be summarized like this: Process-based multitasking handles the concurrent execution of programs. Thread-based multitasking deals with the concurrent execution of pieces of the same program.

In the preceding discussions, it is important to clarify that true concurrent execution is possible only in a multiple-CPU system in which each process or thread has unrestricted access to a CPU. For single CPU systems, which constitute the vast majority of systems in use today, only the appearance of simultaneous execution is achieved. In a single CPU system, each process or thread receives a portion of the CPU’s time, with the amount of time determined by several factors, including the priority of the process or thread. Although truly concurrent execution does not exist on most computers, when writing multithreaded programs, you should assume that it does. This is because you can’t know the precise order in which separate threads will be executed, or if they will execute in the same sequence twice. Thus, its best to program as if true concurrent execution is the case.

Multithreading Changes the Architecture of a Program

Multithreading changes the fundamental architecture of a program. Unlike a single-threaded program that executes in a strictly linear fashion, a multithreaded program executes portions of itself concurrently. Thus, all multithreaded programs include an element of parallelism. Consequently, a major issue in multithreaded programs is managing the interaction of the threads.

As explained earlier, all processes have at least one thread of execution, which is called the main thread. The main thread is created when your program begins. In a multithreaded program, the main thread creates one or more child threads. Thus, each multithreaded process starts with one thread of execution and then creates one or more additional threads. In a properly designed program, each thread represents a single logical unit of activity.

The principal advantage of multithreading is that it enables you to write very efficient programs because it lets you utilize the idle time that is present in most programs. Most I/O devices, whether they are network ports, disk drives, or the keyboard, are much slower than the CPU. Often, a program will spend a majority of its execution time waiting to send or receive data. With the careful use of multithreading, your program can execute another task during this idle time. For example, while one part of your program is sending a file over the Internet, another part can be reading keyboard input, and still another can be buffering the next block of data to send.