Understanding Multithreading in C++ Programming Language: Concurrent Execution and Thread Management
Multithreading is a specialized form of multitasking, a feature that enables your computer to run multiple programs simultaneously. In general, multitasking is divided into two types:
process-based and thread-based.Process-based multitasking handles concurrent program execution, while thread-based multitasking manages concurrent execution of segments within the same program. Multithreading in C++ provides the ability to execute multiple threads within a single program, enabling parallelism and improved performance in handling concurrent tasks.
In a multithreaded program, two or more sections can run concurrently. Each segment, known as a thread, defines an independent execution path.
Prior to C++11, there was no built-in support for multithreaded applications, relying solely on the operating system for this feature.
This tutorial assumes you’re on a Linux OS and will guide you through creating a multi-threaded C++ program using POSIX threads. POSIX Threads (Pthreads) provide an API available on Unix-like POSIX systems such as Linux, macOS, and others.
Creating Threads
The following function creates a POSIX thread:
#include <pthread.h>
pthread_create(thread, attr, start_routine, arg)
pthread_create
generates a new thread, making it executable.- It can be called multiple times from anywhere in your code.
- Parameters:
thread
: A unique identifier for the new thread returned by the function.attr
: An attribute object used to set thread attributes (NULL for defaults).start_routine
: The function the thread will execute upon creation.arg
: An argument passed tostart_routine
.
Note: The maximum threads a process can create is system-dependent. Threads are peers without implied hierarchy; one thread can create others.
Terminating Threads
To explicitly exit a thread, use the pthread_exit()
function:
#include <pthread.h>
pthread_exit(status)
- Call
pthread_exit()
after a thread completes its work and isn’t needed. - If
main()
exits before created threads, usingpthread_exit()
lets those threads continue. - Threads created as joinable can be explicitly terminated with
pthread_join()
. - Detached threads can’t be joined and are automatically terminated when
main()
finishes.
Example: Creating Threads
This code creates five threads using pthread_create()
, with each thread printing “Hello World!” and terminating via pthread_exit()
:
#include <iostream>
#include <cstdlib>
#include <pthread.h>
using namespace std;
#define NUM_THREADS 5
void *PrintHello(void *threadid) {
long tid;
tid = (long)threadid;
cout << "Hello World! Thread ID: " << tid << endl;
pthread_exit(NULL);
}
int main () {
pthread_t threads[NUM_THREADS];
int rc;
int i;
for (i = 0; i < NUM_THREADS; i++) {
cout << "main(): Creating thread " << i << endl;
rc = pthread_create(&threads[i], NULL, PrintHello, (void *)i);
if (rc) {
cout << "Error: Unable to create thread, " << rc << endl;
exit(-1);
}
}
pthread_exit(NULL);
}
Passing Arguments to Threads
You can pass multiple arguments using a structure. This example uses a structure to pass arguments to threads:
#include <iostream>
#include <cstdlib>
#include <pthread.h>
using namespace std;
#define NUM_THREADS 5
struct thread_data {
int thread_id;
char *message;
};
void *PrintHello(void *threadarg) {
struct thread_data *my_data;
my_data = (struct thread_data *) threadarg;
cout << "Thread ID: " << my_data->thread_id;
cout << " Message: " << my_data->message << endl;
pthread_exit(NULL);
}
int main () {
pthread_t threads[NUM_THREADS];
struct thread_data td[NUM_THREADS];
int rc;
int i;
for (i = 0; i < NUM_THREADS; i++) {
cout << "main(): Creating thread " << i << endl;
td[i].thread_id = i;
td[i].message = "This is a message";
rc = pthread_create(&threads[i], NULL, PrintHello, (void *)&td[i]);
if (rc) {
cout << "Error: Unable to create thread, " << rc << endl;
exit(-1);
}
}
pthread_exit(NULL);
}
Joining and Detaching Threads
Use pthread_join()
to block the calling thread until the specified thread terminates:
#include <iostream>
#include <cstdlib>
#include <pthread.h>
#include <unistd.h>
using namespace std;
#define NUM_THREADS 5
void *wait(void *t) {
int i;
long tid;
tid = (long)t;
sleep(1);
cout << "Sleeping in thread " << endl;
cout << "Thread with id: " << tid << " ...exiting " << endl;
pthread_exit(NULL);
}
int main () {
int rc;
int i;
pthread_t threads[NUM_THREADS];
pthread_attr_t attr;
void *status;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
for (i = 0; i < NUM_THREADS; i++) {
cout << "main(): Creating thread " << i << endl;
rc = pthread_create(&threads[i], &attr, wait, (void *)i);
if (rc) {
cout << "Error: Unable to create thread, " << rc << endl;
exit(-1);
}
}
pthread_attr_destroy(&attr);
for (i = 0; i < NUM_THREADS; i++) {
rc = pthread_join(threads[i], &status);
if (rc) {
cout << "Error: Unable to join, " << rc << endl;
exit(-1);
}
cout << "Main: Completed thread id: " << i ;
cout << " Exiting with status: " << status << endl;
}
cout << "Main: Program exiting." << endl;
pthread_exit(NULL);
}
Discover more from PiEmbSysTech
Subscribe to get the latest posts sent to your email.