Threads
We all know that the execution of a program is done by the process, while the actual execution of the code in the process is a thread to complete, it is the real execution flow. Usually a program is called a thread (threads) in a line of practice. A more accurate definition of this is that the thread is "a control sequence within a process." And all processes have at least one thread of execution.
In general, process and thread relationships are
① process is the basic unit of resource competition
② threads are the most small units of a program's line of practice.
Threading Benefits:
· threads consume much less resources than processes, and creating a new thread is much smaller than creating a new process (threads do not have to open virtual address space)
• Switching between threads requires much less work for the operating system than switching between processes
• The ability to take advantage of the number of concurrent processors
• While waiting for slow I/O operations to end, the program can perform other computational tasks
• Compute-intensive applications that can be run on multiprocessor systems to decompose computations into multiple threads
· I/O intensive applications overlap I/O operations for high performance. Threads can wait for different I/O operations at the same time.
Thread disadvantage
1. Performance loss
A computationally-intensive thread that is rarely blocked by external events often cannot share the same processor with its threads. If the number of compute-intensive threads is more than the available processors, then there may be a significant performance penalty, and the performance penalty in this case is to increase the additional synchronization and scheduling overhead, while the available resources are the same.
2. Reduced robustness
Multi-Threading requires more in-depth consideration, in a multithreaded program, because of the small deviations in time allocation or the possibility of sharing the variables that should not be shared, the likelihood is very large, in other words, there is a lack of protection between the threads.
3. Lack of access control
A process is the basic granularity of access control, and invoking some system functions in one thread affects the entire process.
4. High level of programming difficulty
Writing and debugging a multithreaded program is much more difficult than a single thread
return value
The global variable errno is not set when all pthreads processing functions are faulted (and most other POSIX functions do). Instead, the error code is returned by the return value. Pthreads also provides errno variables within the thread to support other code that uses errno. However, for errors in the Pthreads function, it is recommended that the return value industry be judged, because reading the return value is less expensive than reading the errno variable within the thread
Related functions
(1) thread identification
The thread ID is the same as the process ID, but the process ID is unique across the system, but the thread ID is different, and it only makes sense in the context of the process to which it belongs. The thread ID is represented by the pthread_t data type, which is represented by a struct, and the portable system cannot treat it like a pid_t type as an integer. so a function is usually used to compare two thread IDs
int pthread_equal (pthread_t tid1, pthread_t Tid2)
At the same time, the thread can get its own thread ID through pthread_self
pthread_t pthread_self (void);
However, it is worth noting that before a thread does not have a process, it corresponds to a process descriptor in the kernel, corresponding to a process ID. But after introducing the threading concept, the situation has changed, a user process under the jurisdiction of N user-state threads, each thread as a separate scheduling entity in the kernel state has its own process descriptor, the process and the kernel of the descriptor has suddenly become a 1:n relationship, The POSIX standard also requires that all threads in the process return the same process ID when they call the Getpid function
Multithreaded processes, also known as thread groups, each thread within a thread group has a process descriptor structure (TASK_STRUCT) corresponding to it in the kernel. The process descriptor structure of the PID, the surface of the corresponding is the process ID, in fact, it corresponds to the thread ID, the Tgid in the process descriptor, meaning the thread Group ID, it corresponds to the user level of the process ID
Linux provides Gettid system tuning to return its thread ID, but GLIBC does not have the system tuned for use by a programmer in an open connect port. If you do need to get the thread ID, you can use the following method:
#include <sys/syscall.h>= Syscall (Sys_gettid);
Example
#include <stdio.h> #include <sys/syscall.h> #include <pthread.h> #include <unistd.h> void *route (void *arg) { pid_t tid = syscall (Sys_gettid); while (1) { printf ("Tid =%d, pid=%d\n", Tid, Syscall (sys_getpid)); Sleep (1); } } int main (void) { pthread_t myID; Pthread_create (&myid, NULL, route, NULL); pid_t tid = syscall (Sys_gettid); pid_t pid = Syscall (sys_getpid); while (1) { printf ("Tid =%d, pid=%d\n", Tid, PID); Sleep (1); } }
The results are easy to verify.
Note: the-l option in the PS command displays the following information:
LWP: The thread ID, which is the return value of both Gettid () system calls.
NLWP: Number of thread Group threads
And what type of pthread_t is depending on the implementation. For Linux?? NPTL implementation of the current implementation? And, pthread_t type of thread ID, essentially? A process address space? An address.
The traditional process model is described earlier, with only one control thread per process. In the case of POSIX threads: Before creating multithreading, the program is also started with a single control thread in a single process. So there's no difference between a program's behavior and the traditional process. New threads can be created through pthread_create.
(2) Create thread pthread_create function
Prototype: int pthread_create (pthread_t *thread, //thread identifier const pthread_attr_t *attr, //thread property is usually filled with null void * (*start_routline) (void *), //thread callback function void *arg); Parameter NULL for callback function
The creation of a successful thread ID is set to the memory unit that thread points to. The newly created thread executes from the Start_routline address, which has an untyped pointer parameter arg, and if you need to pass more than one parameter to the Start_routeline function, then you need to put these parameters into a struct, and then the address of the struct is passed in.
Example:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> void * Myroute (void *arg) { printf ("This is Thread one\n"); printf ("pid:%d thread one:%lx\n", Getpid (), pthread_self ()); } int main (void) { pthread_t tid; if (pthread_create (&tid, NULL, Myroute, NULL)! = 0) perror ("Can ' t create thread"), exit (1); printf ("pid:%d main thread:%lx\n", Getpid (), pthread_self ()); Sleep (1); printf ("return\n"); }
Change it.
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> void * Myroute (void *arg) { while (1) { printf ("The IS Thread one\n"); printf ("pid:%d thread one:%lx\n", Getpid (), pthread_self ()); } } int main (void) { pthread_t tid; if (pthread_create (&tid, NULL, Myroute, NULL)! = 0) perror ("Can ' t create thread"), exit (1); while (1) { printf ("pid:%d main thread:%lx\n", Getpid (), pthread_self ()); Sleep (1); } printf ("return\n"); }
Note: for the second parameter, attr is used to customize a variety of thread properties, it is usually empty so that the thread has a default property, if you need to set the thread properties, the following two functions are used
#include <pthread.h>//Initialize Thread propertiesIntPthread_attr_init (pthread_attr_t *attr);//Destroying thread PropertiesIntPthread_attr_destroy (pthread_attr_t *attr); Its properties have thread attributes: Detach attribute: Detach state = pthread_create_joinable Snatch resource scope: scope = Pthread_scope_system whether to inherit schedule policy Slightly: Inherit scheduler = pthread_inherit_sched scheduling policy () Scheduling policy = Sched_other //Time- sharing scheduling strategy is Sched_other
Scheduling priority: Scheduling
the reserved area between the 0-wire stacks: Guard size = 4096 bytes /// the thread stack address that is primarily used to ensure thread safety itself: STAC K address = 0x40196000 itself specifies the line Cheng size: Stack size = 0x201000 bytes /c8>
For the detach attribute:
Use the following two functions. They are set separation state and get detach state respectively
int detachstate); pthread_attr_getdetachstate (*detachstate);
Example
#include <pthread.h> #include <stdio.h> #include <stdlib.h> pthread_attr_t attr; void *route (void *arg) { printf ("route1\n");} int main (void) { pthread_t tid; Pthread_attr_init (&attr); Pthread_attr_setdetachstate (&attr, pthread_create_detached); Pthread_create (&tid, &attr, Route, NULL); int ret; Pthread_attr_getdetachstate (&attr, &ret); if (ret = = pthread_create_detached) { printf ("pthread_create_detached\n"); } else if (ret = = Pthread_create_j oinable) { printf ("pthread_create_joinable\n"); } Pthread_attr_destroy (&ATTR); }
Results:
[Email protected]:~/day19$./a . Out pthread_create_detached
(3) The exit Pthread_exit function of the thread
#include <pthread.h>void pthread_exit (void *retval);
The retval parameter is an untyped pointer, similar to a single parameter passed to the startup routine, and be careful not to point it to a local variable. Other threads in the process can access this pointer by calling the Pthread_join function to get the terminating state of the thread.
(4) canceling execution of the thread pthread_cancle function
prototypes int pthread_cancel (pthread_t thread); parameter thread: Thread ID return value: successful return 0; failure return error code
Summary about thread death conditions:
1 when the thread handler function returns;
2.pthread_exit is called (process is dead after all threads in the process die)
3. The thread was called by another thread to cancel the Pthread_cancel function. (It is worth noting that the cancel thread does not exit immediately, but waits until the system calls to the cancel point.) You can call the Pthread_testcancel (void) function to artificially add a cancel)
thread wait and detach
(5) Thread wait function pthread_join
The reason why a thread wait function is required is because the ① has exited the thread and its space is not released, still within the process's address space. ② creating a new thread does not duplicate the address space of the thread you just exited.
#include <pthread.h>int pthread_join (pthread_t thread, void **value_ptr);
Note here that retval is a level two pointer, because it needs to be modified during the execution of the wait thread death. function does not return until the PID thread dies, returns 0 successfully, and fails to return an error code.
At this point, the calling thread blocks until the specified thread calls Pthread_exit, returns from the boot Journey, or is canceled. Thread threads are terminated with different pthread_join methods.
To the terminating state is different:
1. If the thread thread returns by return, *value_ ptr points to a cell that holds the return value of the thread's function.
2. If the thread thread is called by another thread Pthread_ Cancel exception ends, *value_ ptr points to the cell where the constant pthread_ CANCELED is stored.
3. If the thread thread is called Pthread_exit terminated by itself, *valueptr points to a cell that holds the parameters passed to Pthread_exit.
4. If you are not interested in the terminating state of thread threads, you can pass NULL to the Value_ ptr parameter.
If you are not interested in the return value of a thread, you can set the valude_ptr to null (typically empty). In this case, the call to the Pthread_join function can wait for the specified thread to terminate, but not to get the thread's seed state.
(6) Thread separation function
By default, the newly created thread is joinable, and after the thread exits, it needs to be pthread_join, or the resource cannot be freed, causing a system leak.
If you do not care about the return value of a thread, join is a burden, and this time we can tell the system to automatically release thread resources when the thread exits
int Pthread_detach (pthread_t thread);
It is possible for other threads within a thread group to detach a target thread, or a thread to detach itself:
Pthread_detach (Pthread_self ());
Joinable and separation are conflicting, and a thread cannot be both joinable and detached.
Example:
#include <string.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include < unistd.h> #include <pthread.h> void *thread_run (void* arg) { Pthread_detach (pthread_self ()); printf ("%s\n", (char*) arg); return NULL; } int main ( void) { pthread_t tid; Char str[] = "thread1 run ..."; if (Pthread_create (&tid, NULL, Thread_run, str)! = 0) { printf ("Create thread error\n"); return 1; } int ret = 0; Sleep (1); if (Pthread_join (tid, NULL) = = 0) { printf ("Pthread wait success\n"); ret = 0; } else { printf ("Pthread wait failed\n"); ret = 1; } return ret; }
linux--Threads