when a Linux process creates a new thread, the thread will have its own stack because the thread has its own local variables. But share global variables, file descriptors, and current directory status with its creator.
Process and thread
under Linux system, starting a new process must allocate its independent address space and establish many data tables to maintain its code segments, stack segments and data segments, which is an expensive multitasking mode of work.
Compared with processes, threads are a very frugal way of multitasking. Multiple threads running in a process use the same address space, and the time required for switching between threads is far less than that required for switching between processes.
for different processes, they have independent data space. Data transmission can only be carried out through inter process communication. Threads in the same process share data space, so the data of one thread can be directly used by other threads.
a process can be regarded as the basic unit of a resource, and threads are the basic unit of program scheduling. Threads within a process share the time slice obtained by the process.
in addition to the above advantages, multithreaded program, as a multitask and concurrent working mode, has the following advantages:
- Make the multi CPU system more effective: the operating system will ensure that different threads run on different CPUs when the number of threads is not greater than the number of CPUs.
- Improve the program structure: a long and complex process can be divided into multiple threads and become several independent or semi independent running parts. Such a program will be conducive to understanding and modification.
Compile multithreading
since pthread library is not a linux system library, add - lpthread when compiling:
gcc main.c -o main -lpthread
Thread ID
pthread_ The function of self is to obtain the thread ID:
#include <pthread.h> pthread_t pthread_self ( void );
Thread creation
pthread_ The prototype of the create function is as follows. If the call is successful, the return value is 0, otherwise the error code is returned:
#include <pthread.h> int pthread_create ( pthread_t *thread, pthread_attr_t *attr, void * ( *start_routine ) ( void * ), void *arg );
- Thread: points to pthread_ Pointer of type create, used to reference the newly created thread.
- attr: used to set thread properties. Generally, no special properties are required, so it can be simply set to NULL.
- (* start_routine)(void *): pass the address of the function to be executed by the new thread.
- arg: parameter of the function to be executed by the new thread.
pthread_create creates a thread and puts it into the ready state instead of the execution state. When the process executes the sleep function, it hands over cpu control, and the thread can execute. After executing the thread, the thread also disappears.
Parameterless thread
the code is as follows:
#include <stdio.h> #include <pthread.h> #include <unistd.h> void *create ( void *arg ) { printf ( "New thread .... \n" ); printf ( "This thread's id is %u\n", ( unsigned int ) pthread_self() ); printf ( "The process pid is %d\n", getpid() ); return ( void * ) 0; } int main ( int argc, char *argv[] ) { pthread_t tid; int error; printf ( "Main thread is starting ... \n" ); error = pthread_create ( &tid, NULL, create, NULL ); if ( error ) { printf ( "thread is not created ... \n" ); return -1; } printf ( "The main process's pid is %d \n", getpid() ); sleep ( 1 ); return 0; }
Execution results:
Main thread is starting ... The main process's pid is 55 New thread .... This thread's id is 1084225280 The process pid is 55
Threads using simple parameters
the code is as follows:
#include <stdio.h> #include <pthread.h> #include <unistd.h> void *create ( void *arg ) { int *num; num = ( int * ) arg; printf ( "create parameter is %d \n", *num ); return ( void * ) 0; } int main ( int argc, char *argv[] ) { pthread_t tidp; int error; int test = 4; int *attr = &test; error = pthread_create ( &tidp, NULL, create, ( void * ) attr ); if ( error ) { printf ( "pthread_create is created is not created ... \n" ); return -1; } sleep ( 1 ); printf ( "pthread_create is created ...\n" ); return 0; }
Execution results:
create parameter is 4 pthread_create is created ...
Threads using complex parameters
the code is as follows:
#include <stdio.h> #include <pthread.h> #include <unistd.h> #include <stdlib.h> struct menber { int a; char *s; }; void *create ( void *arg ) { struct menber *temp; temp = ( struct menber * ) arg; printf ( "menber->a = %d \n", temp->a ); printf ( "menber->s = %s \n", temp->s ); return ( void * ) 0; } int main ( int argc, char *argv[] ) { pthread_t tidp; int error; struct menber *b; b = ( struct menber * ) malloc ( sizeof ( struct menber ) ); b->a = 4; b->s = ( char * ) "zieckey"; error = pthread_create ( &tidp, NULL, create, ( void * ) b ); if ( error ) { printf ( "phread is not created ...\n" ); return -1; } sleep ( 1 ); printf ( "pthread is created...\n" ); return 0; }
Execution results:
menber->a = 4 menber->s = zieckey pthread is created ...
Thread waiting
pthread_ The prototype of the join function is as follows. It is used to wait for the execution of a thread to end:
#include <pthread.h> int pthread_join ( pthread_t th, void **thread_return );
- th: the thread waiting to end. The thread passes pthread_ The identifier returned by create.
- thread_return: a secondary pointer that points to another pointer that points to the return value of the thread.
After the call completes successfully, pthrea_join returns 0, and any other return value indicates an error.
#include "stdio.h" #include "stdlib.h" #include "string.h" #include "pthread.h" #include <unistd.h> char message[32] = "Hello World"; void *thread_function ( void *arg ); int main ( void ) { pthread_t a_thread; void *thread_result; if ( pthread_create ( &a_thread, NULL, thread_function, ( void * ) message ) < 0 ) { perror ( "fail to pthread_create" ); exit ( -1 ); } printf ( "waiting for thread to finish\n" ); if ( pthread_join ( a_thread, &thread_result ) < 0 ) { perror ( "fail to pthread_join" ); exit ( -1 ); } printf ( "MESSAGE is now %s\n", message ); return 0; } void *thread_function ( void *arg ) { printf ( "thread_function is running, argument is %s\n", ( char * ) arg ); strcpy ( message, "marked by thread" ); }
Execution results:
waiting for thread to finish thread_function is running, argument is Hello World MESSAGE is now marked by thread
You can see that the value of the array message modified by the created new thread can also be accessed by the original thread because the threads share the relevant resources of the process.
Thread termination
If any thread in the process calls exit or Exit, then the whole process will terminate.
the normal exit mode of the thread is as follows:
- The thread returns from the startup routine.
- A thread can be terminated by another process.
- The thread calls pthread itself_ Exit function.
pthread_ The prototype of exit function is as follows:
#include <pthread.h> void pthread_exit ( void *retval );
The parameter retval points to an object that the thread wants to return.
#include <stdlib.h> #include <stdio.h> #include <pthread.h> void *print_message_function ( void *ptr ) { char *message; message = ( char * ) ptr; char * return_message = ( char * ) "thread all done"; printf ( "%s ", message ); printf ( "PID: %ld \n", pthread_self() ); pthread_exit ( return_message ); } int main() { pthread_t thread1, thread2; char *message1 = ( char * ) "Thread 1"; char *message2 = ( char * ) "Thread 2"; int iret1, iret2; void *pth_join_ret1; void *pth_join_ret2; iret1 = pthread_create ( &thread1, NULL, print_message_function, ( void* ) message1 ); iret2 = pthread_create ( &thread2, NULL, print_message_function, ( void* ) message2 ); pthread_join ( thread1, &pth_join_ret1 ); pthread_join ( thread2, &pth_join_ret2 ); printf ( "Thread 1 returns: %d\n", iret1 ); printf ( "Thread 2 returns: %d\n", iret2 ); printf ( "pthread_join 1 returns: %s\n", ( char * ) pth_join_ret1 ); printf ( "pthread_join 2 returns: %s\n", ( char * ) pth_join_ret2 ); exit ( 0 ); }
Execution results:
Thread 1 PID: 140544497379072 Thread 2 PID: 140544488986368 Thread 1 returns: 0 Thread 2 returns: 0 pthread_join 1 returns: thread all done pthread_join 2 returns: thread all done
Thread release
threads in linux have two states:
- joinable state: when the thread function returns, exit, or call pthread_ When exit, the stack and thread descriptor occupied by the thread will not be released. Only when pthread is called_ After joining, these resources will be released.
- unjoinable state: the thread resource exits when the thread function returns, or pthread is called_ When exit, it will be released automatically.
there are two methods to set the unjoinable state:
- When using pthread_create, which is specified when creating a thread.
- Using pthread in a thread_ detach ( pthread_self() ):
#include <pthread.h> #include <stdio.h> #include <unistd.h> void* print_message_function ( void *ptr ); int main ( void ) { pthread_t thread1; while ( 1 ) { pthread_create ( &thread1, NULL, print_message_function, NULL ); printf ( "%ld\n", thread1 ); sleep ( 1 ); } return ( 0 ); } void* print_message_function ( void *ptr ) { pthread_detach ( pthread_self() ); printf ( "This is thread\n" ); pthread_exit ( 0 ); }