thread and thread control

thread

①Thread definition

All execution flows in Linux are called Lightweight Processes (LWPs), lightweight process is also called thread

thread runs inside process -> thread runs inside process address space
insert image description here

In Linux, from the perspective of CPU, can you identify whether the task_struct is a process or a thread?
No, the CPU does not need to identify, the CPU only cares about a single execution flow one by one, and each task_struct is an execution flow

task_struct in the eyes of the CPU<=task_struct of the OS principle

insert image description here

②The advantages of threads

1. Creating a new thread is much less expensive than creating a new process
2. Switching between threads requires much less work from the operating system than switching between processes
3. Threads take up more resources than There are many fewer processes
4. Computation-intensive applications, in order to run on a multi-processor system, decompose the calculation into multiple threads to implement I/O-intensive applications, and overlap I/O operations in order to improve performance. Threads can wait for different I/O operations at the same time

Thread resource sharing is very simple, only need to define global resources, all threads can see

Computation-intensive: Most of the tasks of the execution stream are mainly computing (encryption and decryption, sorting and search)
I/O-intensive: Most of the tasks of the execution stream are mainly I/O (brushing disk, accessing database, access network)

③ Disadvantages of thread

Performance penalty:
A computationally intensive thread that is rarely blocked by external events often cannot share the same processor with other threads. If the number of compute-intensive threads is more than the available processors, there may be a large performance penalty, and a large number of threads adds additional synchronization and scheduling overhead, so the more threads are not the better.

Reduced robustness:
Writing multi-threading requires more comprehensive and in-depth consideration. In a multi-threaded program, there is a high possibility of adverse effects due to subtle deviations in time allocation or sharing variables that should not be shared. Causes thread safety issues; in multi-threading, the crash of a single thread will cause the entire process to crash, and it is difficult to find out which thread crashes, and it is difficult to debug

Lack of access control:
process is the basic granularity of access control, calling some OS functions in one thread will affect the whole process

Increased programming difficulty:
Writing and debugging a multithreaded program is much more difficult than a single-threaded program

④Thread exception

If a single thread divides by zero, the wild pointer problem will cause the thread to crash, and the process will also follow the crashed
thread as the execution branch of the process. If the thread is abnormal, it is similar to the abnormality of the process, and then triggers the signal mechanism to terminate the process. All threads within will exit immediately, and resources will be recycled.

⑤ Process and thread

Process is the basic unit of resource allocation, and thread is the basic unit of scheduling

Thread-unique data:
1. Thread ID
2. A set of registers (saving context, scheduling)
3. Stack (temporary data for threads)

4. errno
5. Signal mask word
6. Scheduling priority

Multiple threads of a process share the same address space, so the data segment and the code segment are shared, and each thread also shares the following process resources and environment:
1. File descriptor table
2. The processing method of each signal
3. The current working directory
4. User id and group id

POSIX thread library

Thread-related functions form a complete series. Most of the names of the functions start with "pthread_". When importing the header file <pthread.h>
to link these thread function libraries, use the compiler command "-lpthread" ” option

① Creation of threads

insert image description here

Parameters:
thread: thread identifier, output parameter
attr: thread attribute can specify the size of the new thread stack, scheduling strategy, if it is NULL, it is the default attribute
star_routine: thread history, callback function, thread entry function
arg: entry function for thread Pass parameters, NULL means no parameters
Return value: 0 is returned for success, error number is returned for failure

Example:

#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
void *Routine(void* arg)//回调
{
    
    
     char* str=(char*) arg;
     while(1)
     {
    
    
       printf("%s:pid:%d,ppid:%d\n",str,getpid(),getppid());
      sleep(1);
    }
}
  int main()
  {
    
    
    pthread_t pt;
    pthread_create(&pt,NULL,Routine,(void*)"i am a new pthread");
    while(1)
    {
    
    
      printf("i am a main pthread:pid:%d,ppid:%d\n",getpid(),getppid());
      sleep(2);
    }
    return 0;
  }                          

insert image description here
It can be seen that although there are two execution streams, it is the same process
to view the current lightweight process: ps -aL
insert image description here

②Get the ID of the thread

insert image description here
Create six threads and get thread IDs in two ways:

  #include<stdio.h>                                                                                                                                         
  #include<unistd.h>
  #include<pthread.h>
  void *Routine(void* arg)//回调
  {
    
    
    char* str=(char*) arg;
    while(1)
    {
    
    
      printf("%s:pid:%d,ppid:%d,tid:%lu\n",str,getpid(),getppid(),pthread_self());
      sleep(1);
    }
  
 }
  int main()
  {
    
    
    pthread_t tid[6];
    for(int i=0;i<6;i++)
    {
    
    
      char buffer[64];
      sprintf(buffer,"thread %d",i);
      pthread_create(&tid[i],NULL,Routine,(void*)buffer);
      printf("%s tid is:%lu\n",buffer,tid[i]);//通过create的输出型参数拿到线程ID
    }
  
    while(1)
    {
    
    
      printf("i am a main pthread:pid:%d,ppid:%d,tid:%lu\n",getpid(),getppid(),pthread_self());
	  sleep(2);
    }
    return 0;
  }           

insert image description here
The thread ID obtained at this time is not the same as the LWP.
These two methods obtain the user-level thread ID, and the LWP obtains the kernel-level thread ID
. In Linux, the thread of the application layer and the LWP of the kernel are in one-to-one correspondence.

③ thread waiting

Like processes waiting, threads also need to be waited to release resources

Why do threads need to wait?
The thread that has exited, its space has not been released, is still in the address space of the process.
Creating a new thread will not reuse the address space of the thread that just exited

insert image description here
retval: Points to the return value of the thread

	 #include<stdio.h>                                                                                                                                       
     #include<stdlib.h>
     #include<unistd.h>
     #include<pthread.h>
     void* Routine(void* arg)//回调
    {
    
    
       char* str=(char*) arg;
       int count=0;
       while(count<5)
      {
    
    
        printf("%s:pid:%d,ppid:%d,tid:%lu\n",str,getpid(),getppid(),pthread_self());
        sleep(1);
        count++;
      }
     return (void*)66666; 
    }
    int main()
    {
    
    
      pthread_t tid[6];
      for(int i=0;i<6;i++)
      {
    
    
        char* buffer=(char*)malloc(64);
        sprintf(buffer,"thread %d",i);
        pthread_create(&tid[i],NULL,Routine,(void*)buffer);
        printf("%s tid is:%lu\n",buffer,tid[i]);//通过create的输出型参数拿到线程ID
      }
    
      for(int i=0;i<6;i++)
      {
    
    
		 void* ret=NULL;//返回码
         pthread_join(tid[i],&ret);//默认阻塞式等待
         printf("i am a main pthread:pid:%d,ppid:%d,tid:%lu,code:%d\n",getpid(),getppid(),pthread_self(),(int)ret);
      }
      printf("wait finish\n");
      return 0;
    }           

insert image description here
The thread only has the exit code, and does not have exception information like the process. The reason is that once the thread is abnormal, the entire process is terminated, the main thread has no chance to join, and the thread robustness is low.

④Thread termination

1.exit: terminate the process thread call will directly terminate the entire process
2.pthread_exit: terminate the thread, equivalent to return
3.pthread_cancel: cancel the thread, usually the main thread cancels the new thread, exit code -1

insert image description here
insert image description here
Not recommended:
the new thread cancels the main thread: after the main thread is canceled, the subsequent code is no longer executed, and the new thread is not affected, continue to execute the code

	#include<stdio.h>                                                                                                                           
    #include<stdlib.h>
    #include<unistd.h>
    #include<pthread.h>
    pthread_t main_thread;
    void* Routine(void* arg)//回调
    {
    
    
      char* str=(char*) arg;
      int count=0;
      while(count<5)
      {
    
    
        printf("%s:pid:%d,ppid:%d,tid:%lu\n",str,getpid(),getppid(),pthread_self());
        sleep(1);
        int ret= pthread_cancel(main_thread);
        printf("%d",ret);                                                 
        printf("已经取消\n");
        count++;
      }
      return NULL;
    }
    
    int main()
    {
    
    
      pthread_t tid[6];
      main_thread=pthread_self();
      for(int i=0;i<6;i++)
      {
    
    
		char* buffer=(char*)malloc(64);
        sprintf(buffer,"thread %d",i);
        pthread_create(&tid[i],NULL,Routine,(void*)buffer);
        printf("%s tid is:%lu\n",buffer,tid[i]);//通过create的输出型参数拿到线程ID
      }

     for(int i=0;i<6;i++)
      {
    
     
        void* ret=NULL;//返回码
        pthread_join(tid[i],&ret);//默认阻塞式等待
        printf("i am a main pthread:pid:%d,ppid:%d,tid:%lu,code:%d\n",getpid(),getppid(),pthread_self(),(int)ret);
      }
      printf("wait finish\n");
      return 0;
    }                         

insert image description here
The first successful cancellation returns 0, and the subsequent cancellation fails to return 3. The
insert image description here
defunct indicates that the thread has been cancelled.

⑤ Thread separation

In general a thread must be waited, just like a process is waited

1. The thread can not be joined, but this needs to separate the thread.
2. After the thread is separated, the thread exits, and the system will automatically recycle the thread resources, so that there is no need to be blocked by join and wait.
3. If you don't care about the return value of the thread, Join is a burden, just use thread separation
4. A thread cannot be both joinable and detachable

insert image description here

  #include<stdio.h>                                                                                                                             
  #include<stdlib.h>
  #include<unistd.h>
  #include<pthread.h>
  pthread_t main_thread;
  void* Routine(void* arg)//回调
  {
    
    
    sleep(1);
    pthread_detach(main_thread);
    char* str=(char*) arg;
    int count=0;
    while(count<5)
    {
    
    
      printf("%s:pid:%d,ppid:%d,tid:%lu\n",str,getpid(),getppid(),pthread_self());
      sleep(1);
      count++;
    }
    return NULL;
  }
  
  int main()
  {
    
    
    pthread_t tid[6];
    main_thread=pthread_self();
    for(int i=0;i<6;i++)
    {
    
    
      char* buffer=(char*)malloc(64);
	  sprintf(buffer,"thread %d",i);
      pthread_create(&tid[i],NULL,Routine,(void*)buffer);
      printf("%s tid is:%lu\n",buffer,tid[i]);//通过create的输出型参数拿到线程ID
    }
    while(1)
    {
    
    
      printf("i am a main pthread:pid:%d,ppid:%d,tid:%lu\n",getpid(),getppid(),pthread_self());
      sleep(1);
    }
    printf("wait finish\n");
    return 0;
  }                                 

insert image description here
The detached thread exits, and the system automatically recycles resources

Thread ID and process address space layout

thread_t is essentially an address

Threads also need to be managed. Linux does not provide real threads, only LWP. OS only performs stream management on the LWP kernel, and other data such as interfaces for users are managed by the thread library pthread, which means that it is described in the library first. organize
insert image description here
insert image description here

insert image description here

secondary page table

64-bit uses multi-level page table, 32-bit actually uses two-level page table mapping.
When there is a table in the mapping relationship, the size of the table is too large, and it needs to be stored in two-level page table.
insert image description here
insert image description here

Guess you like

Origin blog.csdn.net/hbbfvv1h/article/details/122759664