C++ multithreading multithreading is a special form of multitasking that allows a computer to run two or more programs simultaneously. In general, there are two types of multitasking: process-based and thread-based.
Process-based multitasking is the concurrent execution of programs. Thread-based multitasking is the concurrent execution of pieces of the same program. A multithreaded program consists of two or more parts that can be run simultaneously. Each part of such a program is called a thread, and each thread defines a separate execution path.
This tutorial assumes that you are using a Linux operating system, and we will write multithreaded C++ programs using POSIX. POSIX Threads or Pthreads provide apis that are available on many Unix POSIX systems, such as FreeBSD, NetBSD, GNU/Linux, Mac OS X, and Solaris.
Create thread The following program, which we can use to create a POSIX thread:
#include <pthread.h>
pthread_create (thread, attr, start_routine, arg)
Copy the code
Here, pthread_create creates a new thread and makes it executable. Here is a description of the parameters:
parameter | describe |
---|---|
thread | Pointer to thread identifier. |
attr | An opaque property object that can be used to set thread properties. You can specify thread property objects or use the default value NULL. |
start_routine | The starting address of a thread to run a function that will be executed once the thread is created. |
arg | Arguments to run a function. It must be passed by casting the reference as a pointer to void. If no argument is passed, NULL is used. |
When the thread is successfully created, the function returns 0. If the value is not 0, the thread failed to be created.
Terminating a POSIX thread using the following program:
#include <pthread.h>
pthread_exit (status)
Copy the code
In this case, pthread_exit is used to explicitly exit a thread. Normally, the pthread_exit() function is called when the thread has finished its work and no longer needs to exist.
If main() ends before the thread it created and exits via pthread_exit(), the other threads continue. Otherwise, they are automatically terminated at the end of main().
The following simple example code uses the pthread_create() function to create five threads, each of which prints “Hello Runoob!” :
The instance
#include <iostream>
// Mandatory header file
#include <pthread.h>
using namespace std;
#define NUM_THREADS 5
// The thread's running function
void* say_hello(void* args)
{
cout << "Hello Runoob!" << endl;
return 0;
}
int main(a)
{
// Define the thread ID variable. Multiple variables use arrays
pthread_t tids[NUM_THREADS];
for(int i = 0; i < NUM_THREADS; ++i)
{
// The arguments are: the id of the created thread, the argument of the thread, the function called, the argument of the function passed
int ret = pthread_create(&tids[i], NULL, say_hello, NULL);
if(ret ! =0)
{
cout << "pthread_create error: error_code="<< ret << endl; }}// Wait for each thread to exit before the process terminates, otherwise the process is forced to end, the thread may not respond;
pthread_exit(NULL);
}
Copy the code
Compile the following program using the -lpThread library:
$ g++ test.cpp -lpthread -o test.o
Copy the code
Now, executing the program produces the following results:
$./test.o Hello Runoob! Hello Runoob! Hello Runoob! Hello Runoob! Hello Runoob!Copy the code
The following simple example code creates five threads using the pthread_create() function and receives the parameters passed in. Each thread prints a “Hello Runoob!” Message, output the received arguments, and call pthread_exit() to terminate the thread.
The instance
// File name: test.cpp
#include <iostream>
#include <cstdlib>
#include <pthread.h>
using namespace std;
#define NUM_THREADS 5
void *PrintHello(void *threadid)
{
// Cast the passed argument from an untyped pointer to an integer pointer, and then read
int tid = *((int*)threadid);
cout << "Hello Runoob! Thread ID," << tid << endl;
pthread_exit(NULL);
}
int main (a)
{
pthread_t threads[NUM_THREADS];
int indexes[NUM_THREADS];// Use an array to hold the value of I
int rc;
int i;
for( i=0; i < NUM_THREADS; i++ ){
cout << "Main () : Create thread," << i << endl;
indexes[i] = i; // Save the value of I
// When passed, it must be cast to void*, i.e., no type pointer
rc = pthread_create(&threads[i], NULL,
PrintHello, (void *)&(indexes[i]));
if (rc){
cout << "Error: could not create thread," << rc << endl;
exit(- 1); }}pthread_exit(NULL);
}
Copy the code
Now compile and execute the program, which produces the following results:
$ g++ test.cpp -lpthread -o test.o
$ ./test.o
main(a): Create a thread,0Main () : Creates a thread,1Hello Runoob! The thread ID,0Main () : Create thread, Hello Runoob! The thread ID,21Main () : Creates a thread,3Hello Runoob! The thread ID,2Main () : Creates a thread,4Hello Runoob! The thread ID,3Hello Runoob! The thread ID,4
Copy the code
Passing parameters to a thread this example demonstrates how to pass multiple parameters through a structure. You can pass any data type in the thread callback because it points to void, as shown in the following example:
The instance
#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 (a)
{
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 = (char*)"This is 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);
}
Copy the code
When the above code is compiled and executed, it produces the following results:
$ g++ -Wno-write-strings test.cpp -lpthread -o test.o
$ ./test.o
main(a) : creating thread, 0
main() : creating thread, 1
Thread ID : 0 Message : This is message
main() : creating thread, Thread ID : 21
Message : This is message
main() : creating thread, 3
Thread ID : 2 Message : This is message
main() : creating thread, 4
Thread ID : 3 Message : This is message
Thread ID : 4 Message : This is message
Copy the code
Join and detach threads We can use two functions to join or detach threads:
Pthread_join (threaDID, status) pthread_detach (threaDID) The pthread_join() subroutine prevents calling the program until the specified threaDID thread terminates. When you create a thread, one of its properties defines whether it is joinable or detached. Only threads defined as connectable at creation time can be connected. If a thread is defined as separable when it is created, it can never be joined.
This example demonstrates how to use the pthread_join() function to wait for a thread to complete.
The instance
#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 (a)
{
int rc;
int i;
pthread_t threads[NUM_THREADS];
pthread_attr_t attr;
void *status;
// Initialize and set the thread to joinable.
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], NULL, wait, (void *)&i );
if (rc){
cout << "Error:unable to create thread," << rc << endl;
exit(- 1); }}// Delete attributes and wait for other threads
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);
}
Copy the code
When the above code is compiled and executed, it produces the following results:
main() : creating thread, 0
main() : creating thread, 1
main() : creating thread, 2
main() : creating thread, 3
main() : creating thread, 4
Sleeping in thread
Thread with id : 4. exiting Sleeping in thread Thread with id :3. exiting Sleeping in thread Thread with id :2. exiting Sleeping in thread Thread with id :1. exiting Sleeping in thread Thread with id :0. exiting Main: completed thread id :0 exiting with status :0
Main: completed thread id :1 exiting with status :0
Main: completed thread id :2 exiting with status :0
Main: completed thread id :3 exiting with status :0
Main: completed thread id :4 exiting with status :0
Main: program exiting.
Copy the code