Pthread and Linux

Source: Internet
Author: User
Tags posix

Pthread is a set of user-level thread libraries, but kernel-level threads are used for implementation on Linux. The advantage is that the concurrency of programs can be fully improved, the thread can also call functions such as head as before, without worrying that the running of other threads will be affected by the competition. but in this way, the Linux thread is not standard.

Next we will talk about pthread in combination with the Implementation on Linux.

Basic Concepts
---------

Pthread is a set of common thread libraries, which are widely supported by various Unix systems and proposed by POSIX. therefore, it has good customer portability. in Linux, because it is implemented through kernel-level threads, it is not fully implemented. however, it is not inferior in terms of functionality.

First, let's look at the following example in the pipeline:
/* ------ Test. c -------*/
# Include
Void * PP (void * Arg)
{
While (1 ){
Printf (/"% S // n/", (char *) Arg );
Sleep (2 );
}
Return NULL;
}

Main ()
{
Pthread_t PID;
Pthread_create (& pid, null, PP,/"Hello World /");
While (1 ){
Printf (/"I am main thread // n /");
Sleep (1 );
}
}

GCC test. C-lpthread
./A. Out

I am main thread
Hello World
I am main thread
Hello World
............

At the beginning of the program, the system created a main thread and a new sub-thread with pthread_create. In this way, the two threads run simultaneously and print things to the screen.

A thread is actually a function. After being created, it is executed immediately and the thread ends when the function returns.

The following function is used to create a new thread:
Int pthread_create (pthread_t * thread,
Pthread_attr_t * ATTR,
Void * (* start_routine) (void *),
Void * Arg );

The first parameter is a pthread_t pointer used to save the thread ID. Future operations on this thread will be marked with ID.
The second parameter is a pthread_attr_t pointer used to describe the attributes of the thread to be created. null indicates that the default attributes are used.
The third parameter specifies the port of a thread. It is a function with only one (void *) parameter.
The fourth parameter specifies the parameter to be passed to a thread, such as a port function.

This is very simple. You should understand the above example.
As I mentioned above, Linux threads do not need to block other threads, So programming is very convenient.

Binary Return Value
-------

It should also be seen that the return value of each thread is void *.
There are two methods to return:
1 return pointer;
2 pthread_exit (pointer );
The two methods are the same.

So how do other threads obtain the returned value?
Use this function:
Int pthread_join (pthread_t th, void ** thread_return );

A thread has two States. joinable indicates that the system retains the return value of the thread until another thread removes it. The detach system does not retain the return value.

The following function is used for detach:
Int pthread_detach (pthread_t th );

Pthread_t pthread_self (); you can return your own ID. Generally, we use the following
To detach itself:
Pthread_detach (pthread_self ());

Three mutex
--------

Mutex is used to solve the mutex problem. A mutex is a mutex device used to protect the critical section and shared memory. It has two statuses: Locked and unlocked. It cannot be owned by both threads at the same time.

The following functions are used to process mutex:

Initialize a mutex
Int pthread_mutex_init (pthread_mutex_t * mutex, const
Pthread_mutexattr_t * mutexattr );
Lock a mutex
Int pthread_mutex_lock (pthread_mutex_t * mutex ));
Attempts to lock a mutex
Int pthread_mutex_trylock (pthread_mutex_t * mutex );
Lock a mutex
Int pthread_mutex_unlock (pthread_mutex_t * mutex );
Destroy a mutext
Int pthread_mutex_destroy (pthread_mutex_t * mutex );

There are three types of locks:/"Fast/",/"recursive/", or/"error checking /"
When the lock operation is performed:
In the unlock status
Lock it and make it belong to itself.

When it is locked by other threads,
Suspends the current thread until it is unlocked by another thread.

When it is locked by itself,
/"Fast/" suspends the current thread.
/"Resursive/" succeeded and immediately returned the number of times currently locked
/"Error checking/" returns edeadlk immediately

During the unlock operation:
Unlock.
/"Fast/" wake up the first locked thread
/"Recursive/" reduces the number of locks (This number is only locked by itself, not by other threads). When the number of locks is equal to zero, and wake up the first locked thread.
/"Error check/" checks whether it is locked by itself. If it is not returned, eperm is used to wake up the first locked thread,

Generally, we use some static variables to initialize mutex.
/"Fast/" 'pthread _ mutex_initializer/
/"Recursive/" 'pthread _ recursive_mutex_initializer_np/
/"Error check/" 'pthread _ errorcheck_mutex_initializer_np/

Note: _ NP indicates no portable cannot be transplanted.

For example:
/// "Fast/" type mutex
Pthread_mutex_t mutex = pthread_mutex_initializer;
......
Pthread_mutext_lock (& mutex );
Fwrite (buffer, 1, strlen (buffer), file );
Pthread_mutex_unlock (& mutex );
......

It seems a little hard to understand. It is easy to compile several programs by yourself.

Four condition variable (condition variable)
------------------------------

It is also a device used for synchronization, allowing a process to suspend itself and wait for a condition variable to be changed.
There are several functions:

Int pthread_cond_init (pthread_cond_t * cond,
Pthread_condattr_t * cond_attr );
Int pthread_cond_signal (pthread_cond_t * Cond );
Int pthread_cond_broadcast (pthread_cond_t * Cond );
Int pthread_cond_wait (pthread_cond_t * cond,
Pthread_mutex_t * mutex );
Int pthread_cond_timedwait (pthread_cond_t * cond,
Pthread_mutex_t * mutex,
Const struct timespec * abstime );
Int pthread_cond_destroy (pthread_cond_t * Cond );

I want to see the names to know their purpose. Usually we also use static variables to initialize a conditional variable.
Example:
Pthread_cond_t cond = pthread_cond_initializer;

Pthread_cond_signal is used to wake up a locked thread.
Pthread_cond_broadcast is used to wake up all locked threads.

Pthread_cont_wait is used to wait.
To solve the competition problem (that is, a thread is just going to wait and another thread is already signal ),
Metux.

Take a look at the following example:

Int X, Y;
Pthread_mutex_t mut = pthread_mutex_initializer;
Pthread_cond_t cond = pthread_cond_initializer;

// Waiting until X is greater than Y is saved med as follows:

Pthread_mutex_lock (& MUT );
While (x <= y ){
Pthread_cond_wait (& cond, & MUT );
}
/* Operate on x and y */
Pthread_mutex_unlock (& MUT );

The execution process of pthread_cond_wait is as follows:
1. First, it unlocks the mutex and then suspends the current thread.
2. When it is awakened, it will lock the mutex.

This ensures that this is a critical section.

Five thread-specific data (TSD)
----------------------------

To put it bluntly, it is the static variables used in the thread. You can easily understand why using static variable functions is not a line.
(That is, they must be carefully used in the thread ).

The use of static variables is very convenient, which produces thread-specific data. It can be understood
A pointer array, but it is unique for each thread.

Example:
Int func ()
{
Char * P;
P = strdup (thread-specific-data [1]);
......
}

Void x pthread-1 (void * Arg)
{
......
Func ()
......
}

Void x pthread-2 (void * Arg)
{
......
Func ()
......
}

Different threads call func to produce different results. This is just an example.

Int pthread_key_create (pthread_key_t * Key, void
(* Destr_function) (void *));
Int pthread_key_delete (pthread_key_t key );
Int pthread_setspecific (pthread_key_t key, const void
* Pointer );
Void * pthread_getspecific (pthread_key_t key );

TSD can be regarded as an array of void.
Note: pthread_key_delete only releases the space occupied by the key. You still need to release
Void *.

To deepen your understanding, let's take a look at the following example:
/* Key for the thread-specific buffer */
Static pthread_key_t buffer_key;

/* Once-only initialisation of the key */
Static pthread_once_t buffer_key_once = pthread_once_init;

/* Allocate the thread-specific buffer */
Void buffer_alloc (void)
{
Pthread_once (& buffer_key_once, buffer_key_alloc );
Pthread_setspecific (buffer_key, malloc (100 ));
}

/* Return the thread-specific buffer */
Char * get_buffer (void)
{
Return (char *) pthread_getspecific (buffer_key );
}

/* Allocate the key */
Static void buffer_key_alloc ()
{
Pthread_key_create (& buffer_key, buffer_destroy );
}

/* Free the thread-specific buffer */
Static void buffer_destroy (void * BUF)
{
Free (BUF );
}

6. Signal Processing
------------

The signal processing in the thread is like this. All threads share a group of signal processing functions.
Each thread has its own signal mask.

The following functions are used to process thread signals:
Int pthread_sigmask (INT how, const sigset_t * newmask,
Sigset_t * oldmask );
Int pthread_kill (pthread_t thread, int signo );
Int sigwait (const sigset_t * Set, int * sig );

You can use sigaction to install the signal processing function.

Take a look at the following program:
# Include
# Include
Void * PP (void *)
{
Printf (/"ha ha /");
Alarm (1 );
}
Void main_alarm (int I)
{
Printf (/"Main got // n /");
Alarm (3 );
}

Main ()
{
Pthread_t PID;
Struct sigaction AA;
Sigset_t sigt;

Sigfillset (& sigt );
AA. sa_handler = mainalarm;
AA. sa_mask = sigt;
AA. sa_flags = 0;
Sigaction (sigalrm, & aa, null );

Pthread_create (& pid, null, PP, null );
While (1 );
Return 0;
}

7. Give up (Cancellation)
-----------------------

This is a mechanism in which a thread can end another thread. Specifically, a thread can
Sends a cancellation request to another thread. The other thread can ignore
This request can be processed when a cancellation point is reached.

When a thread processes a cancellaction request, pthread_exit calls
Cleanup handlers is used. The so-called cancellation point is in these places, the thread will
Processing cancellation request. POSIX function: pthread_join
Pthread_cond_wait pthread_cond_timewait pthread_testcancel sem_wait
Sigwait is a cancellation point. The following system functions are also a cancellation point:
Accept open sendmsg
Close pause sendto
Connect read System
Fcntl Recv tcdrain
Fsync recvfrom wait
Lseek recvmsg waitpid
Msync send write
Nanosleep

If other functions call the above functions, they are also the cancellation points.
Int pthread_setcancelstate (INT state, int * oldstate );
Used to allow or disable cancellation,
The state can be pthread_cancel_enable pthread_cancel_disable.

Int pthread_setcanceltype (INT type, int * oldtype );
Set how to handle cancellation, asynchronous or delayed.
The type can be pthread_cancel_asynchronous pthread_cancel_deferred.
Void pthread_testcancel (void );

8. Cleanup handlers)
-------------------------------

These functions are called in sequence by pthread_exit. They are managed in stack style.
This mechanism aims to release some occupied resources before exiting.

For example, we use a mutex, but we want to unlock it during cancellation.

Pthread_cleanup_push (pthread_mutex_unlock, (void *) & MUT );
Pthread_mutex_lock (& MUT );
/* Do some work */
Pthread_mutex_unlock (& MUT );
Pthread_cleanip_pop (0 );

Note:
During asynchronous processing, a cancellation can occur in pthread_cleaup_push
And pthread_mutex_lock. This is very bad. Therefore, asynchronous Cancellation
Is very difficult to use.

Void pthread_cleanup_push (void (* routine) (void *), void * Arg );
Void pthread_cleanup_pop (INT execute );
If execute is not equal to 0, it will be executed once after the stack is released.

9. semaphores)
-----------------------

Semaphores is a resource counter shared by threads.
The basic semaphores operation is: Increase the semaphores of the atom, reduce the semaphores of the atom, and wait
The semaphore value is non-zero.

In POSIX, the semaphore has a maximum value. The macro sem_value_max defines this value.
In libc, the value is equal to int_max (too large ).

The following are related functions:

Int sem_init (sem_t * SEM, int pshared, unsigned int value );
Initialize a semaphore with the value of value. pshared indicates whether it is shared.
0 indicates local, and non-0 indicates global.

Int sem_destroy (sem_t * SEM );
Release related resources.

Int sem_wait (sem_t * SEM );
Wait until the SEM value is non-zero.

Int sem_trywait (sem_t * SEM );

Int sem_post (sem_t * SEM );
Add the semaphore to 1.

Int sem_getvalue (sem_t * SEM, int * sval );
Obtain the semaphore value.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.