Overview
Multi-threaded programs, as a multi-task and concurrent working method, have the following advantages:
1) Improve application response. This is especially meaningful for graphic interface programs. When an operation takes a long time, the entire system will wait for this operation. At this time, the program will not respond to keyboard, mouse, and menu operations, but will use multithreading technology, putting time consuming in a new thread can avoid this embarrassing situation.
2) Make the multi-CPU system more effective. The operating system ensures that different threads run on different CPUs when the number of threads is not greater than the number of CPUs.
3) Improve the program structure. A long and complex process can be considered to be divided into multiple threads and become several independent or semi-independent running parts. Such a program will facilitate understanding and modification.
In Linux, the most common is the POSIX standard pthread library. Pthread is implemented by calling clone (), a Linux-specific system call.
The most basic concepts involved in multi-threaded development include:Thread, mutex lock, Condition.
Among them, thread operations are divided into three types: thread creation, exit, and wait.
Mutex locks include creation, destruction, locking, and unlocking.
Conditional operations include creation, destruction, triggering, broadcast, and waiting.
Other thread extension concepts, such as signal lights, can be encapsulated through the basic operations of the above three basic elements.
Table 1. thread function list
Object |
Operation |
Linux pthread API |
Windows SDK library APIs |
Thread |
Create |
Pthread_create |
Createthread |
Exit |
Pthread_exit |
Threadexit |
Wait |
Pthread_join |
Waitforsingleobject |
Mutex lock |
Create |
Pthread_mutex_init |
Createmutex |
Destroy |
Pthread_mutex_destroy |
Closehandle |
Lock |
Pthread_mutex_lock |
Waitforsingleobject |
Unlock |
Pthread_mutex_unlock |
Releasemutex |
Condition |
Create |
Pthread_cond_init |
Createevent |
Destroy |
Pthread_cond_destroy |
Closehandle |
Trigger |
Pthread_cond_signal |
Setevent |
Broadcast |
Pthread_cond_broadcast |
Setevent/resetevent |
Wait |
Pthread_cond_wait/pthread_cond_timedwait |
Singleobjectandwait |
1. Thread creation and Termination
1.1) pthread_t
The identifier type of the thread. pthread_t is defined in the header file/usr/include/bits/pthreadtypes. h.
Typedef unsigned long int pthread_t;
1.2) pthread_create
Thread_create is used to create a thread. Its prototype is:
Extern int pthread_create _ p (pthread_t * _ thread,
_ Const pthread_attr_t * _ ATTR,
Void * (* _ start_routine) (void *),
Void * _ Arg ));
The first parameter is the pointer to the thread identifier,
The second parameter is used to set the thread attribute and set it to a null pointer. This will generate the thread with the default attribute,
The third parameter is the starting address of the thread-running function,
The last parameter is the parameter for running the function,
When the thread is successfully created, the function returns 0. If the value is not 0, the thread creation fails. The common error codes returned are eagain and einval. The former indicates that the system restricts the creation of new threads. For example, the number of threads is too large. The latter indicates that the second parameter indicates that the thread attribute value is invalid. After the thread is successfully created, the newly created thread runs the function with parameters 3 and 4, and the original thread continues to run the next line of code.
1.3) pthread_join
The pthread_join function is used to wait for the end of a thread. Function prototype:
Extern int pthread_join _ p (pthread_t _ th,
Void ** _ thread_return ));
The first parameter is the identifier of the waiting thread,
The second parameter is a user-defined pointer that can be used to store the return values of the waiting thread.
This function is a thread-blocking function. The function called will wait until the end of the waiting thread. When the function returns, the resources of the waiting thread will be reclaimed.
1.4) pthread_exit
In addition to the normal execution of a thread, you can use the pthread_exit function to end it. The prototype of the pthread_exit function is as follows:
Extern void pthread_exit _ p (void * _ retval) _ attribute _ (_ noreturn __));
The unique parameter is the return code of the function. As long as the second thread_return parameter in pthread_join is not null, this value will be passed to thread_return.
Finally, it should be noted that a thread cannot be waited by multiple threads. Otherwise, the first thread that receives the signal will return success, and the other threads that call pthread_join will return the error code esrch.
2. Modify thread attributes
The property structure is pthread_attr_t, which is defined in the header file/usr/include/pthread. h.
The initialized function is pthread_attr_init, which must be called before the pthread_create function.
Attribute objects mainly includeBind?,Separated?,Stack address,Stack size,Priority. The default attributes are non-bound, non-separated, 1 MB stacks by default, and have the same priority as the parent process.
2.1) thread binding
Thread binding involves another concept: Light process (lwp: Light Weight process ). A lightweight process can be understood as a kernel thread, which is located between the user layer and the system layer. The system allocates thread resources and controls threads through lightweight processes. A lightweight process can control one or more threads. By default, the number of light processes started and the light processes to control which threads are controlled by the system are called unbound. Under the binding condition, a thread is bound to a light process. The bound thread has a high response speed because the CPU time slice is scheduled to light processes. The bound thread can ensure that there is always a light process available when needed. By setting the priority and scheduling level of the bound process, the bound thread can meet requirements such as real-time response.
The function used to set the thread binding status is pthread_attr_setscope. It has two parameters: the first is the pointer to the attribute structure, and the second is the binding type. It has two values: pthread_scope_system (bound) and pthread_scope_process (unbound ).
The following code creates a bound thread.
Pthread_attr_t ATTR;
Pthread_t tid;
/* Initialize the property value, which is set to the default value */
Pthread_attr_init (& ATTR );
Pthread_attr_setscope (& ATTR, pthread_scope_system );
Pthread_create (& tid, & ATTR, (void *) my_function, null );
2.2) about the thread status: Separation/non-separation
The separation status of a thread determines how a thread terminates itself. In the preceding example, we use the default attribute of the thread, that is, the thread is not in the detached state. In this case, the original thread waits for the creation of the thread to end. Only when the pthread_join () function returns, the created thread is terminated and the system resources occupied by it can be released. The separation thread is not like this. It is not waiting by other threads. When the running ends, the thread is terminated and system resources are released immediately. Programmers should select appropriate separation States based on their own needs.
The function used to set the thread separation status is
Pthread_attr_setdetachstate (pthread_attr_t * ATTR, int detachstate)
The second parameter can be pthread_create_detached and pthread _ create_joinable ).
Note that if you set a thread as a separate thread and the thread runs very fast, it is likely to terminate before the pthread_create function returns, after it is terminated, it may hand over the thread number and system resources to other threads for use. In this way, the thread that calls pthread_create gets the wrong thread number. To avoid this situation, you can take some synchronization measures. One of the simplest methods is to call the pthread_cond_timewait function in the created thread, so that the thread can wait for a while, leave enough time for the function pthread_create to return. Setting a wait time is a common method in multi-threaded programming. However, do not use functions such as wait (), which sleep the entire process and cannot solve the thread synchronization problem.
2.3) thread priority
Thread priority, which is stored in the schema sched_param. Use the pthread_attr_getschedparam function and the pthread_attr_setschedparam function to store the data. Generally, we always take the priority and modify the obtained value before storing it back.
The thread priority value range is-20 ~ 20. The higher the value, the lower the priority. The default value is 0. This parameter is valid only when the scheduling policy is real-time (sched_rr or sched_fifo,
When running, use the pthread_setschedparam () function to change.
Pthread_attr_t ATTR;
Pthread_t tid;
Sched_param Param;
Int newprio = 20;
Pthread_attr_init (& ATTR );
Pthread_attr_getschedparam (& ATTR, Param );
Param. sched_priority = newprio;
Pthread_attr_setschedparam (& ATTR, Param );
Pthread_create (& tid, & ATTR, (void *) myfunction, myarg );