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