WEB DEVELOPER SITE
PYTHONPHPJAVA
 

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 a program.
  • Thread-based multitasking is the concurrent execution of fragments of the same program.

Multithreaded programs contain two or more parts that can 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 are going to write a multithreaded C++ program using POSIX. APIs provided by POSIX Threads or Pthreads are available on a variety of Unix-like POSIX systems, such as FreeBSD, NetBSD, GNU/Linux, Mac OS X, and Solaris.

Create thread

The following program, we can use it to create a POSIX thread:

#include <pthread.h>
pthread_create (thread, attr, start_routine, arg) 

Here, pthread_create creates a new thread and makes it executable. The following is a description of the parameters:

The
Parameters Description
thread points to the thread identifier pointer.
attr An opaque property object that can be used to set thread properties. You can specify a thread attribute object or use the default value of NULL.
start_routine thread runs the function start address and is executed once the thread is created.
arg Parameters of the run function. It must be passed by casting the reference as a pointer to a void type. If no arguments are passed, NULL is used.

When the thread is created successfully, the function returns 0. If the return value is not 0, the thread creation fails.

Terminate thread

Using the following program, we can use it to terminate a POSIX thread:

#include <pthread.h>
pthread_exit (status) 

Here, pthread_exit is used to explicitly exit a thread. Normally, the pthread_exit() function is called when the thread does not need to continue to exist after it has finished working.

If main() ends before the thread it creates and exits via pthread_exit(), the other threads will continue to execute. Otherwise, they will be automatically terminated at the end of main().

example

The following simple example code creates 5 threads using the pthread_create() function, and each thread outputs "Hello welookups!":

example

#include <iostream> // Required header file #include <pthread.h> using namespace std; #define NUM_THREADS 5 // Thread run function void* say_hello(void* args) { cout << "Hello welookups!" << endl; return 0; } int main() { // Define the thread's id variable, multiple variables using an array pthread_t tids[NUM_THREADS]; for(int i = 0; i < NUM_THREADS; ++i) { // The parameters are: thread id created, thread parameters, function called, function passed in int ret = pthread_create(&tids[i], NULL, say_hello, NULL); if (ret != 0) { cout << "pthread_create error: error_code=" << ret << endl; } } // After each thread exits, the process ends, otherwise the process is forced to end, and the thread may not respond.; pthread_exit(NULL); }

Compile the following program with the -lpthread library:

$ g++ test.cpp -lpthread -o test.o

Now, executing the program will produce the following results:

$ ./test.o
Hello welookups!
Hello welookups!
Hello welookups!
Hello welookups!
Hello welookups!

The following simple example code creates 5 threads using the pthread_create() function and receives the passed arguments. Each thread prints a "Hello welookups!" message and outputs the received parameters, then calls pthread_exit() to terminate the thread.

example

//filename:test.cpp #include <iostream> #include <cstdlib> #include <pthread.h> using namespace std; #define NUM_THREADS 5 void *PrintHello(void *threadid) { //Force type conversion on incoming parameters, change from untyped pointer to integer pointer, and then read int tid = *((int*)threadid); cout << "Hello welookups! Thread ID, " << tid << endl; pthread_exit(NULL); } int main () { 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 first //Must be cast to a void* type when passed in, ie no type pointer rc = pthread_create(&threads[i], NULL, PrintHello, (void *)&(indexes[i])); if (rc){ cout << "Error: Unable to create thread" << rc << endl; exit(-1); } } pthread_exit(NULL); }

Compiling and executing the program now will produce the following results:

$ g++ test.cpp -lpthread -o test.o
$ ./test.o
Main() : create thread, 0
Main() : create thread, 1
Hello welookups! thread ID, 0
Main() : create thread, Hello welookups! thread ID, 21

Main() : create thread, 3
Hello welookups! Thread ID, 2
Main() : create thread, 4
Hello welookups! thread ID, 3
Hello welookups! Thread ID, 4

Pass parameters to the thread

This example demonstrates how to pass multiple parameters through a structure. You can pass any data type in a thread callback because it points to void, as shown in the following example:

example

#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 = (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); }

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() : 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

Connect and detach threads

We can use the following two functions to connect or detach threads:

Pthread_join (threadid, status)
Pthread_detach (threadid)

The pthread_join() subroutine blocks the calling program until the specified threadid thread terminates. When a thread is created, one of its properties defines whether it is joinable or detachable. Only threads that are defined as connectable at creation time can be connected. If a thread is defined as separable when it is created, it can never be connected.

This example demonstrates how to use the pthread_join() function to wait for a thread to complete.

example

#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; // Initialize and set the thread to be connectable(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 the attribute 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); }

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.