I. POSIX thread attributes
The POSIX thread library defines the thread attribute object pthread_attr_t, which encapsulates the thread attributes that can be accessed and modified by the thread creator. It mainly includes the following attributes:
1. Scope)
2. stack size)
3. Stack address)
4. Priority)
5. detached state)
6. Scheduling Policy and Parameters)
The thread property object can be associated with one thread or multiple threads. When a thread attribute object is used, it is the configuration of thread and thread group behavior. All threads that use property objects will have all the properties defined by the property objects. Although they share property objects, they maintain their independent thread IDs and registers.
Threads can compete for resources in two competing regions:
1. Process scope: other threads in the same process
2. system scope: With all threads in the system
The scope attribute describes the resources that a specific thread will compete. A thread with a system domain will compete with all threads with a system domain in the system to schedule processor resources according to the priority.
A separate thread is a thread that does not need to be synchronized with other threads in the process. That is to say, no thread will wait for the separation thread to exit the system. Therefore, once the thread exits, its resources (such as the thread ID) can be reused immediately.
The thread layout is embedded in the process layout. Processes have code segments, data segments, and stack segments, while threads share code segments and data segments with other threads in the process. Each thread has its own stack segment, this stack segment is allocated in the stack segment of the process address space. The size of the thread stack is set when the thread is created online. If this parameter is not set during creation, the system specifies a default value. The size of the default value depends on the specific system.
The following table lists the attributes of threads that can be set in a POSIX thread attribute object and their meanings:
Function |
Attribute |
Description |
Int pthread_attr_setdetachstate (Pthread_attr_t * ATTR, int detachstate) |
Detachstate |
The detachstate attribute controls whether a thread is Is detachable |
Int pthread_attr_setguardsize (Pthread_attr_t * ATTR, size_t guardsize) |
Guardsize |
The guardsize attribute sets the overflow of the newly created thread stack. Reserve size |
Int pthread_attr_setinheritsched (Pthread_attr_t * ATTR, int inheritsched) |
Inheritsched |
Inheritsched decides how to set a new creation Scheduling attributes of threads |
Int pthread_attr_setschedparam (Pthread_attr_t * ATTR, Const struct sched_param * restrict PARAM) |
Param |
Param is used to set the priority of the newly created thread. |
Int pthread_attr_setschedpolicy (Pthread_attr_t * ATTR, int Policy) |
Policy |
Policy is used to set the scheduling of the first-created thread Policy |
Int pthread_attr_setscope (Pthread_attr_t * ATTR, Int contentionscope) |
Contentionscope |
Contentionscope is used to set a new line Scope |
Int pthread_attr_setstack (Pthread_attr_t * ATTR, void * stackader, size_t stacksize) |
Stackader Stacksize |
Both determine the base address of the thread stack. And the minimum size of the stack (in bytes) |
Int pthread_attr_setstackaddr (pthread _ attr_t * ATTR, void * stackader) |
Stackader |
Stackader determines the stack base address of the newly created thread. |
Int pthread_attr_setstacksize (pthread_attr_t * ATTR, size_t stacksize)
Stacksize determines the minimum stack size of the newly created thread.
The scheduling policies and priorities of processes belong to the main thread. In other words, setting the scheduling policies and priorities of processes only affects the scheduling policies and priorities of the main thread, the scheduling policy and priority of the peer-to-peer thread will not be changed (this sentence is not completely correct ). Each peer thread can have its own scheduling policies and priorities independent of the main thread.
In Linux, a process has three scheduling policies: sched_fifo, sched_rr, and sched_other. The thread is no exception.
In the pthread library, a function is provided to set the scheduling attribute of the created thread: It inherits the scheduling attribute (scheduling policy and priority) from the Creator thread ), or set the scheduling attribute from the property object. This function is:
Int pthread_attr_setinheritsched (pthread_attr_t * ATTR, int inherit) where the value of inherit is one of the following values:
Enum
{
Pthread_inherit_sched, // The thread scheduling attribute is inherited from the Creator thread
Pthread_explicit_sched // set the thread scheduling attribute to the attribute set by ATTR.
};
If you call this function to set the parameter to pthread_inherit_sched when creating a new thread, When you modify the priority of the process, all threads in the process that inherit this priority and have not changed its priority will also change the priority (that is, the reason why the above sentence is correct ).
Let's write a program to test it:
C ++ code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
|
# Include <unistd. h> # Include <sys/types. h> # Include <pthread. h># Include <stdlib. h> # Include <stdio. h> # Include <errno. h> # Include <string. h> # Define err_exit (m )\ Do \ {\ Perror (m );\ Exit (exit_failure );\ } While (0) Int main (void) { Pthread_attr_t ATTR; Pthread_attr_init (& ATTR ); Int state; Pthread_attr_getdetachstate (& ATTR, & State ); If (State = pthread_create_joinable) Printf ("detachstate: pthread_create_joinable \ n "); Else if (State = pthread_create_detached) Printf ("detachstate: pthread_create_detached "); Size_t size; Pthread_attr_getstacksize (& ATTR, & size ); Printf ("stacksize: % d \ n", size ); Pthread_attr_getguardsize (& ATTR, & size ); Printf ("guardsize: % d \ n", size ); Int scope; Pthread_attr_getscope (& ATTR, & scope ); If (scope = pthread_scope_process) Printf ("Scope: pthread_scope_process \ n "); If (scope = pthread_scope_system) Printf ("Scope: pthread_scope_system \ n "); Int policy; Pthread_attr_getschedpolicy (& ATTR, & Policy ); If (Policy = sched_fifo) Printf ("policy: sched_fifo \ n "); Else if (Policy = sched_rr) Printf ("policy: sched_rr \ n "); Else if (Policy = sched_other) Printf ("policy: sched_other \ n "); Int inheritsched; Pthread_attr_getinheritsched (& ATTR, & inheritsched ); If (inheritsched = pthread_inherit_sched) Printf ("inheritsched: pthread_inherit_sched \ n "); Else if (inheritsched = pthread_explicit_sched) Printf ("inheritsched: pthread_explicit_sched \ n "); Struct sched_param Param; Pthread_attr_getschedparam (& ATTR, & PARAM ); Printf ("sched_priority: % d \ n", Param. sched_priority ); Pthread_attr_destroy (& ATTR ); Return 0; } |
When calling each function to set the attributes of a thread property object, you must first call pthread_attr_init to initialize this object, and finally call pthread_attr_destroy to destroy this object.
Simba @ Ubuntu :~ /Documents/code/linux_programming/UNP/pthread $./pthread_attr
Detachstate: pthread_create_joinable
Stacksize: 8388608
Guardsize: 4096
Scope: pthread_scope_system
Policy: sched_other
Inheritsched: pthread_inherit_sched
Sched_priority: 0
Ii. Thread-specific data
In a single-threaded program, we often use global variables to share data among multiple functions.
In a multi-threaded environment, global variables are shared by all threads because data space is shared.
However, sometimes it is necessary to provide a global variable private to the thread in the application design, which is valid only in a thread, but can be accessed across multiple functions.
POSIX thread library solves this problem by maintaining a certain data structure, which is called (thread-specific data, or TSD ).
The related functions are as follows:
Int pthread_key_create (pthread_key_t * Key, void (* destructor) (void *));
Int pthread_key_delete (pthread_key_t key );
Void * pthread_getspecific (pthread_key_t key );
Int pthread_setspecific (pthread_key_t key, const void * value );
Int pthread_once (pthread_once_t * once_control, void (* init_routine) (void ));
Pthread_once_t once_control = pthread_once_init;
After pthread_key_create is called, The pthread_key_t value of the thread-specific data (TSD) visible to all threads is generated. After pthread_setspecific is called, the specific data of each thread is bound to pthread_key_t, although there is only one pthread_key_t, the specific data of each thread is independent of the memory space. When the thread exits, it will execute destructor
Function.
C ++ code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
|
# Include <unistd. h> # Include <sys/types. h> # Include <pthread. h># Include <stdlib. h> # Include <stdio. h> # Include <errno. h> # Include <string. h> # Define err_exit (m )\ Do \ {\ Perror (m );\ Exit (exit_failure );\ } While (0) Typedef struct TSD { Pthread_t tid; Char * STR; } Tsd_t; Pthread_key_t key_tsd; Pthread_once_t once_control = pthread_once_init; Void destroy_routine (void * value) { Printf ("destory... \ n "); Free (value ); } Void once_routine (void) { Pthread_key_create (& key_tsd, destroy_routine ); Printf ("Key init... \ n "); } Void * thread_routine (void * Arg) { Pthread_once (& once_control, once_routine ); Tsd_t * value = (tsd_t *) malloc (sizeof (tsd_t )); Value-> tid = pthread_self (); Value-> STR = (char *) ARG; Pthread_setspecific (key_tsd, value ); Printf ("% s setspecific PTR = % P \ n", (char *) Arg, value ); Value = pthread_getspecific (key_tsd ); Printf ("tid = 0x % x STR = % s PTR = % P \ n", (INT) Value-> tid, value-> STR, value ); Sleep (2 ); Value = pthread_getspecific (key_tsd ); Printf ("tid = 0x % x STR = % s PTR = % P \ n", (INT) Value-> tid, value-> STR, value ); Return NULL; } Int main (void) { // Pthread_key_create (& key_tsd, destroy_routine );
Pthread_t tid1; Pthread_t tid2; Pthread_create (& tid1, null, thread_routine, "thread1 "); Pthread_create (& tid2, null, thread_routine, "thread2 "); Pthread_join (tid1, null ); Pthread_join (tid2, null ); Pthread_key_delete (key_tsd ); Return 0; } |
The main thread creates two threads and then joins them to wait for them to exit. The execution function for each thread is thread_routine, and thread_routine calls pthread_once, this function indicates that if the first thread calls it, it will execute once_routine and then return it from once_routine, that is, pthread_once. Other subsequent threads will not execute once_routine when calling it, to call pthread_key_create only once, a pthread_key_t is generated.
Value.
In the thread_routine function, the Data Type of a specific thread is customized. For different threads, the TSD content is different. Assume that thread 1 enters sleep after printing for the first time, thread 2 also starts to execute and call TSD and key_t of pthread_setspecific bound to thread 2. At this time, thread 1 calls pthread_getspecific and returns the TSD pointer bound to key_t, which is still the TSD pointer of thread 1, that is, although there is only one key_t, each thread has its own TSD.
Simba @ Ubuntu :~ /Documents/code/linux_programming/UNP/pthread $./pthread_tsd
Key init...
Thread2 setspecific PTR = 0xb6400468
Tid = 0xb6d90b40 STR = thread2 PTR = 0xb6400468
Thread1 setspecific PTR = 0xb6200468
Tid = 0xb7591b40 STR = thread1 PTR = 0xb6200468
Tid = 0xb7591b40 STR = thread1 PTR = 0xb6200468
Destory...
Tid = 0xb6d90b40 STR = thread2 PTR = 0xb6400468
Destory...
Here, TID is the thread ID, STR is the parameter passed to thread_routine, and we can see that there are two different PTR.
Refer:
UNP
Fireside evening speech-multi-core multi-thread Discussion