1. Introduction
Currently, many popular multi-task operating systems provide the thread mechanism. A thread is a single sequential control flow in a program. Multi-threaded program design is to divide a program (process) task into multiple parts (threads) for execution, and each thread is an ordered single control flow, all threads are executed concurrently. In this way, multi-threaded programs can implement parallel computing and efficiently utilize multi-processor. Threads can be divided into user-level threads and kernel-level threads. User-level threads do not require Kernel support and can be implemented in user programs. Thread Scheduling, synchronization, and mutex must be completed by the user program. Kernel-level threads require kernel participation. The kernel completes Thread Scheduling and provides corresponding system calls. User Programs can use these interface functions to control and manage threads. The Linux operating system provides the LinuxThreads library, which is a kernel-level multi-thread function library compliant with POSIX1003.1c standards. The linuxthreads Library provides some key functions for multi-threaded programming, including pthread. H files.
2. Key library functions in LinuxThread
2.1 thread creation and Termination
Int pthread_create (pthread_t * pthread, const pthread_attr_t * attr, void * (* start_routine (* void), void * arg); call this function to create a new thread, after the new thread is created, execute the program specified by start_routine. The attr parameter is the attribute of the thread to be created. If it is NULL, it indicates that the thread is created with the default attribute. Arg is a parameter passed to start_routine. When a new thread is successfully created, the system automatically allocates a thread ID for the new thread and returns it to the caller through pthread.
Void pthread_exit (void * value_ptr); call this function to exit the thread. The value_ptr parameter is a pointer to the returned status value.
2.2 thread control functions
Pthread_self (void); To differentiate threads, the system assigns a unique idnumber to the thread when it is created, which is returned to the caller by pthread_create (). You can also use pthread_self () obtain your own thread ID.
Int pthread_join (pthread-t thread, void ** status); this function is used to wait for the end of a thread. The thread that calls pthread_join () will be suspended until the thread ID specified by the thread parameter is terminated.
Int pthread_detach (pthread_t pthread); The pthread parameter indicates that once the thread is terminated, all resources occupied by the thread are released immediately.
2.3 mutex between threads
The mutex is similar to that in the critical section. Only threads with mutex have the permission to access resources. Because only one mutex object exists, it determines that resource code or variables are shared under any circumstances) will not be accessed by multiple threads at the same time. Mutual exclusion can not only achieve resource security sharing in different threads of the same application, but also achieve secure resource sharing among threads of different applications. In Linux, pthread_mutex_t is used to define the mutex mechanism to complete the mutex operation. The specific operation functions are as follows:
Pthread_mutex_init (pthread_mutex_t * mutex, const pthread_mutexattr_t * attr); Create a mutex variable mutex according to the attr attribute. If the attr parameter is NULL, is created by default.
Pthread_mutex_lock (pthread_mutex_t * mutex); lock a mutex variable. If the mutex specified mutex has been locked, the calling thread will be blocked until the mutex thread has been unlocked.
Pthread_mutex_unlock (pthread_mutex_t * mutex); unlock the mutex variable specified by mutex.
2.4 synchronization between threads
Synchronization means that a thread waits for an event. When a waiting event occurs, the waiting thread and the event continue to run together. If the waiting event does not arrive, it is suspended. In linux, conditional variables are used for synchronization.
Pthread_cond_init (pthread_cond_t * cond, const pthread_cond_t * attr); this function converts a condition variable cond according to the attributes specified by attr.
Pthread_cond_wait (pthread_cond_t * cond, pthread_mutex_t * mutex); wait for an event condition variable), and the calling thread automatically blocks until the corresponding condition variable is set to 1. Threads in the waiting state do not occupy CPU time.
Pthread_cond_signal (pthread_cond_t * cond); Removes the blocking status of a thread waiting for the condition variable specified by the cond parameter.
3. multi-threaded Programming Application Example
Here, multithreading technology is used to implement producer and consumer problems. The producer thread writes data to a buffer zone and the consumer thread reads data from the buffer zone. Because the producer thread and consumer thread share the same buffer zone, to read and write data correctly, the Buffer Queue must be mutually exclusive. The producer thread and consumer thread must satisfy the following requirements: the number of buffer written by the producer cannot exceed the buffer capacity, and the number of read by the consumer cannot exceed the number of write by the producer. A small trick is used in the program to determine whether the buffer is empty or full. At the beginning, the read pointer and write pointer are 0. If the read pointer is equal to the write pointer, the buffer is empty. If (write pointer + 1) % N is equal to the read pointer, the buffer is full. % indicates taking the remainder. In this case, a unit is actually empty and unused. The following are complete program sections and comments.
# Include <stdio. h>
# Include <pthread. h>
# Define BUFFER_SIZE 8
Struct prodcons {
Int buffer [BUFFER_SIZE];
Pthread_mutex_t lock; // mutex LOCK
Int readpos, writepos;
Pthread_cond_t notempty; // judge non-empty buffer Condition
Pthread_cond_t notfull; // condition determination when the buffer is not full
};
Void init (struct prodcons * B ){
Pthread_mutex_init (& B-> lock, NULL );
Pthread_cond_init (& B-> notempty, NULL );
Pthread_cond_init (& B-> notfull, NULL );
B-> readpos = 0;
B-> writepos = 0;
}
Void put (struct prodcons * B, int data ){
Pthread-_ mutex_lock (& B-> lock );
If (B-> writepos + 1) % BUFFER_SIZE = B-> readpos)
{
Pthread_cond_wait (& B-> notfull, & B-> lock );
}
B-> buffer [B-> writepos] = data;
B-> writepos ++;
If (B-> writepos> = BUFFER_SIZE)
B-> writepos = 0;
Pthread_cond_signal (& B-> notempty );
Pthread_mutex_unlock (& B-> lock );
}
Int get (struct prodcons * B ){
Int data;
Pthread_mutex_lock (& B-> lock );
If (B-> writepos = B-> readpos)
{
Pthread_cond _ wait (& B-> notempty, & B-> lock );
}
Data = B-> buffer [B-> readpos];
B-> readpos ++;
If (B-> readpos> = BUFFER_SIZE)
B-> readpos = 0;
Pthread_cond_signal (& B-> notfull );
Pthread_mutex_unlock (& B-> lock );
Return data;
}
# Define OVER (-1)
Struct prodcons buffer;
Void * producer (void * data)
{
Int n;
For (n = 0; n <10000; n ++)
{
Printf ("% d \ n", n );
Put (& buffer, n );
}
Put (& buffer, OVER );
Return NULL;
}
Void * consumer (void * data)
{
Int d;
While (1)
{
D = get (& buffer );
If (d = OVER)
Break;
Printf ("% d \ n", d );
}
Return NULL;
}
Int main (void)
{
Pthread_t th_a, th_ B;
Void * retval;
Init (& buffer );
Pthread_create (& th_a, NULL, producer, 0 );
& Nbsp; pthread_create (& th_ B, NULL, consumer, 0 );
Pthread_join (th_a, & retval );
Pthread_join (th_ B, & retval );
Return 0;
}
In the preceding example, the producer writes integers from 1 to 1000 to the buffer, while the consumer reads and prints the written integers from the same buffer. Because the producer and consumer are two threads running at the same time, and the same buffer zone is used for data exchange, a mechanism must be used for synchronization. Through the above example, we can see that the biggest advantage of Multithreading is that almost all data except the stack is shared, so inter-thread communication efficiency is very high; disadvantages: because all data is shared, it is very easy to cause data corruption between threads. This must be noted during programming.
4. Conclusion
In Linux, the POSIX-based multi-thread technology is well supported, which reduces the system overhead During Concurrent execution of programs and improves the working efficiency of computers. In the specific programming process, we should understand the relationship between threads, and also consider the protection of shared data to ensure efficient code operation under the mutex and synchronization mechanisms, use gcc-D-REENTRANT-libpthread during program compilation. xx. so filename. c compilation.