Threads and sub-threads

Table of contents

1. Introduction

thread        

Main thread and sub-thread

Threads and Processes

Concurrency and Parallelism

2. Code writing

1. Each thread that creates a thread has an independent thread function

verify

2. Create the same thread function shared by each thread

verify

3. Reclaim thread resources (blocking)

verify

 4. Separate threads (not blocked)

verify

5. Thread cancellation and exit

verify

 6. Thread cancellation

VerificationEdit

Three, the properties of the thread

1. Set thread separation, modify the address and size of the thread's stack

verify

 2. Create multi-thread

verify


 

1. Introduction

thread        

        A thread is the smallest unit that participates in system scheduling. It is included in the process and is the actual running unit in the process. A thread refers to a single sequential control flow (or execution route, execution flow) in a process. Multiple threads can be created in a process, and multiple threads can run concurrently. Each thread performs a different task. For example, if an application has designed two tasks task1 and task2 that need to run concurrently, two different tasks can be placed in two threads respectively.

        When the application is started, the system creates a process, which can be regarded as just a container, which contains information such as data structures and environment variables required for thread operation. Multiple threads in the same process will share all system resources in the process, such as virtual address space, file descriptors, signal handling, and so on. However, multiple threads in the same process have their own call stack (call stack, we call it thread stack), their own register context, and their own thread-local storage. A thread does not exist alone, but is included in a process. It is the basic unit that participates in system scheduling and can be executed concurrently. Each thread in the same process can share the resources owned by the process.

Main thread and sub-thread

        When a program starts, a process is created by the operating system (OS), and at the same time a thread runs immediately. This thread is usually called the main thread of the program (Main Thread) because it runs when the program starts. thread. The application starts running with main() as the entry point, so the main() function is the entry function of the main thread, and the tasks performed by the main() function are the tasks that the main thread needs to perform

        Therefore, it can be seen that any process contains a main thread, and a process with only the main thread is called a single-threaded process. Thread process, then naturally there is a multi-thread process. The so-called multi-thread refers to other threads besides the main thread. Other threads are usually created by the main thread (call pthread_create to create a new thread, then the created new thread It is the sub-thread of the main thread.
        Other new threads (that is, sub-threads) are created by the main thread;
        the main thread usually ends at the end and performs various cleaning tasks, such as recycling each sub-thread

Threads and Processes

        A process can create multiple sub-processes to achieve concurrent processing of multi-tasks (essentially, multiple single-threaded processes), and multi-threading can also be achieved (a multi-threaded process). To meet the needs of concurrent processing of multi-tasks, how to choose needs to distinguish between advantages and disadvantages

        Disadvantages of multi-process programming: Multiple processes run at the same time (referring to running at the same time at the macro level), and at the micro level they still switch and run in turn. The cost of switching between processes is much greater than the cost of switching between multiple threads of the same process, usually for some small and medium-sized applications Not cost-effective for programs; inter-process communication is cumbersome. Each process is in its own address space, independent and isolated from each other, and in different address spaces, so communicating with each other is more troublesome. Multi-threading
        can make up for the above problems: the overhead of switching between multiple threads of the same process is relatively small; Communication between multiple threads of a process is easy. They share the address space of the process, so they are all in the same address space, and communication is easy; the speed of thread creation is much faster than the speed of process creation; multi-threading has more advantages on multi-core processors

        Compared with multi-process programming, the advantages of multi-threaded programming are more obvious. In practical applications, multi-threading is far more
widely used than multi-process applications. That being the case, why does there still exist a multi-process programming model? Of course not, multi-threading also has its disadvantages and disadvantages. For example, multi-threaded programming is difficult, and the requirements for programmers' programming skills are relatively high, because many issues need to be considered in a multi-threaded environment, such as thread safety issues and signal processing issues. etc. Writing and debugging a multi-threaded program is
much more difficult than a single-threaded program, etc. Disadvantages, multi-process programming is usually used in some large-scale application programs, such as web server applications, and is less used in small and medium-sized applications

Concurrency and Parallelism

        Serial: refers to a sequential execution, such as completing task1 first, then task2, until task2 is completed, then task3, until task3 is completed... each thing is completed in order, and the previous thing must be completed To do the next thing, there is only one execution unit, which is running serially
 

serial run

         Parallel is completely different from serial. Parallel means that multiple tasks can be executed side by side/parallel. Such a system usually has multiple execution units, so it can run in parallel, such as running task1, task2, and task3 in parallel.

run in parallel

         Parallel operation does not have to start running and end running at the same time, it only needs to satisfy that there are multiple tasks being run by multiple execution units at the same time in a certain period of time

run in parallel 2

         Compared with serial and parallel, concurrency emphasizes a kind of time-division multiplexing. The difference from serial is that it does not have to wait for the completion of the previous task before doing the next task, and can interrupt the currently executing task to switch to execute the next one. Any, that's time division multiplexing. On the same execution unit, divide the time into different segments (time slices), execute each task for a period of time, and switch to execute the next task when the time is up, and perform round-robin training in turn (crossover/alternate execution), which is concurrent operation

run concurrently

 Vivid metaphors seen on the Internet are used to illustrate the differences between the three concepts of serial, parallel and concurrent

⚫ You are halfway through your meal, and the phone comes, and you don't answer the phone until after you finish eating, which means that you don't support concurrency or parallelism, just serial. [One thing, one thing to do]
⚫ You are halfway through your meal, and the phone call comes, you stop eating to answer the phone, and continue to eat after the call, which means that you support concurrency.

        【Alternately do different things】
⚫ You eat half of your meal, and the phone calls, and you eat while talking on the phone, which means you support parallelism. 【Do different things at the same time】

2. Code writing

1. Each thread that creates a thread has an independent thread function

         Use the pthread_create function to create two processes, the thread identifier addresses are tid1 and tid2, the thread attribute structure address is NULL (usually set to NULL), the entry address of the thread function is pthread_fun1 and fun2, and the functions of these two functions are Print i++, one output number, one output ascll code, and finally the parameters passed to the thread function, and finally press the Enter key to exit the program.

        When pthread_create()the function is called, the function returns immediately and leaves the thread running in the background. Therefore, after calling the function in the main thread pthread_create()and passing the parameters, the main thread will continue to execute (in this case, the calling getchar()function is waiting for user input), and the newly created thread will run in the background. If no getchar()function is called or the program encounters no other blocking statements, the program will run until manually stopped. Therefore, although the newly created thread enters an infinite loop, the main thread will continue to execute.

verify

        At this time, it will continue to cycle downwards and increase, and press the Enter key to stop 

2. Create the same thread function shared by each thread

        The code is almost the same as above, just share a thread function 

verify

         Each thread has its own counter. In this code, each thread has a separate local variable i, and they each independently increment their own counter. So when the first thread prints out i=1, it only affects that thread's local variables i, not the other thread's local variables i. When the second thread starts running, its local variables iwill start at 0, not 1.

3. Reclaim thread resources (blocking)

         The pthread_join function waits for the thread to end (this function will block) and reclaims thread resources, similar to the wait() function of a process. If the thread has ended, the function returns immediately.

verify

 4. Separate threads (not blocked)

        Separate the recycling work of the thread When the thread ends, the thread reclaims resources by the system. Separate the calling thread from the current process. The separation does not mean that the thread does not depend on the current process. The purpose of thread separation is to hand over the recovery of thread resources to the system to complete automatically. That is to say, when the separated thread ends, the system Its resources are automatically reclaimed. Therefore, this function does not block

          The code after thread separation is run by the main thread and thread 2, and they run in the same process. So, in this program, the main thread and thread 2 can access the same variables and resources and can communicate with each other. Since the code they run is the same, the content they print out is also the same, and they will not be printed separately like the parent and child processes.

verify

         In this code, the child thread and the main thread/thread 2 are running at the same time, and the output result is indeterminate. It may occur that the main thread/thread 2 executes before the sub-thread, and it may also occur that the sub-thread executes prior to the main thread/thread 2. Therefore, in the test results, it may be that the child thread has completed some loop iterations before the main thread/thread 2 prints "A", causing the output number to skip some values, such as from 0 directly to 2 or from 2 directly to 4.

In multithreaded programming, since threads execute concurrently, their execution order is undefined. Therefore, when writing a multi-threaded program, it is necessary to consider issues such as inter-thread communication and race conditions to avoid unpredictable errors.

5. Thread cancellation and exit

        Exits the calling thread. Multiple threads in a process share the data segment of the process, so usually the resources occupied by the thread will not be released after the thread exits

         A child thread is created, and the output data is printed in a continuous loop. When the counter i is equal to 5, the child thread exits normally by calling the pthread_exit function. In the main function, use the pthread_join function to reclaim the sub-thread resource and wait for the sub-thread to complete, so as to ensure that the operation of the sub-thread is completely completed before ending the main thread. Finally, the main function prints out a "thread ended" message

        Usually, when a thread exits normally, the resources it occupies (such as stacks, registers, etc.) are not released immediately, but are kept in the process. These resources will exist until the process itself ends or other threads call related system functions to release these resources.

        In this code, the child thread occupies a certain resource space, but after the child thread exits normally, no system function is called to release these resources. Therefore, after waiting for the child thread to complete in the main thread, these resources will still remain in the process until the process ends. It should be noted that although its resources may not be released immediately when the thread exits, the operating system will be responsible for managing these resources to ensure that they will not cause too much impact on the system.

verify

 6. Thread cancellation

        Kill (cancel) a thread, cancel itself, and other threads of the current process. Killing the thread is not done immediately, it must reach the cancellation point. A cancellation point is a place where a thread checks to see if it has been canceled and takes action as requested

        In multithreaded programming, if a thread is performing some blocking operations (such as I/O operations, waiting for locks, sleeping, etc.), the thread may not be able to respond to cancellation requests. To avoid this from happening, we can call some blocking operations "cancellation points" and set the cancellation status at these cancellation points.

         In this code, the cancellation point is "sleep (1)", and the child thread sleeps by calling the sleep function, and outputs data every 1 second. Since the sleep function is a cancelable blocking operation, when the sub-thread sleeps, if the main thread calls the pthread_cancel function to cancel the sub-thread, the sub-thread can be terminated at the next cancellation point. If no cancellation point is set, even if the main thread calls the pthread_cancel function, the child thread may continue to run and will not exit until the sleep time is over. It should be noted that although the sleep function is a cancellation point, not all blocking operations are cancelable. In actual programming, we need to select the appropriate blocking operation according to the specific scenario, and add cancellation points and cancellation status processing where necessary.

verify

         When the main thread sleeps for 5 seconds, it will call the pthread_cancel function to send a cancellation request to the child thread. At this time, the child thread is executing the sleep(1) operation, and the corresponding cancellation point is before the next call to the sleep function. Therefore, when the child thread completes the fourth loop iteration and prints the data of i=3, it enters the next sleep state, and is terminated by the cancel request sent by the main thread at that moment. Therefore, the final value of i is 4, that is, the child thread normally outputs data 4 times

Three, the properties of the thread

        The pthread_attr_t structure is a data type used to set thread attributes, and it is usually used to define and initialize various properties of threads. By setting different thread attributes, we can control the thread priority, stack size, thread scheduling strategy and other parameters to meet the different requirements of the program for thread execution.

typedef struct
 {          int etchstate; // thread separation state          int schedpolicy; // thread scheduling policy          struct sched_param schedparam; // thread scheduling parameter          int inheritsched; // thread inheritance          int scope; // thread scope          size_t guardsize ; //The warning buffer size at the end of the thread stack          int stackaddr_set; //The thread stack setting          void* stackaddr; //The position of the thread stack          size_t stacksize; //The size of the thread stack  } pthread_attr_t;









Using the pthread_attr_t data type, we can set the attributes of the thread through the following functions:

  • pthread_attr_init: Initialize thread attributes for subsequent setting operations.
  • pthread_attr_setdetachstate: Set the detachment state of the thread to determine whether the thread needs to be recycled.
  • pthread_attr_setschedpolicy: Set the thread scheduling policy, including SCHED_OTHER, SCHED_FIFO, SCHED_RR and other options.
  • pthread_attr_setschedparam: Set thread scheduling parameters, including thread priority and time slice size, etc.
  • pthread_attr_setstacksize: Set the stack size of the thread to ensure that the thread can run normally

 When creating a thread, set the thread separation through the thread attribute, define the save, separate first, and then execute the thread

1. Set thread separation, modify the address and size of the thread's stack

         After calling the getchar function, the main thread will be blocked, and the child thread is still executing and printing output. When the user inputs a character and presses the Enter key, the getchar function returns the character and unblocks the main thread, the program continues to execute, and executes the return 0 statement to exit the main function.

verify

 2. Create multi-thread

experience it

         Read the task name and running time entered by the user, and then run the fun() function by creating a new thread, passing the user input as an argument. In each loop, the program will ask the user to input the new task name and running time, and store it in the MSG structure. After that, it creates a new thread tid, calls the pthread_create() function to start the thread, and passes the MSG structure pointer to the thread.

        In the fun() function, dereference the MSG structure into a variable of the MSG type, and perform corresponding processing. The fun() function contains a loop that prints the task name and remaining time and sleeps every second

verify

         Because this is just an experience, the code is not optimized, after entering the first task name and execution time, it will continue to print, the information displayed at this time will not look friendly, but you can still continue to enter tasks 2, 3.. .. and when

Guess you like

Origin blog.csdn.net/weixin_46829095/article/details/129705592