Network Programming thread

Source: Internet
Author: User
Tags signal handler

Thread Basic Functions

When a program is started with only one main thread, to implement basic operations on other threads, you must first create a new thread, and the new thread creation can be implemented using the Pthread_create function, which has the following API definitions:

/* Function: Create new Thread; * Return value: 0 If successful, return positive error code if error; * Function prototype: */#include <pthread.h>int pthread_create (pthread_t *tid, const p thread_attr_t *attr,                    void* (*func) (void*), void *arg);/* Description: * When the function returns successfully, the memory unit pointed to by the TID is set to the thread ID of the newly created thread; The attr parameter is used to set the properties of the thread, which, if NULL, is used to create the thread with the default attribute; * The newly created thread runs from the address of the Func function with only one parameter arg; * If you need to pass multiple arguments to the Func function, you must wrap the parameters that need to be passed into a struct , * and then pass the address of the struct as the arg parameter; */

In a process, if the function exit,_exit, or _exit, is called, the process terminates, as well, if the thread in the process calls these three functions, it also terminates the process where the thread is located. So what if you just want to retire the thread and not terminate the process? Here are three ways to exit a thread in single-threaded mode (the process where the thread is not terminated):
    1. The thread is simply returned from the startup routine, and the return value is the thread's exit code;
    2. The thread is canceled by another thread of the same process;
    3. The thread calls the Pthread_exit function;
Once a thread has been created, after performing the task, we can call the Pthread_exit function to terminate a thread, the function's API is defined as follows:
/* Function: Terminate a thread; * return value: none; * Function prototype: */#include <pthread.h>void pthread_exit (void *status);/* Description: * If this thread is not in a detached state, its thread ID and fallback The Out status code will be persisted to some other thread within the calling process to invoke the Pthread_join function on it; * status is to pass its exit information to the collector of the thread, and the information will not be returned to the caller after execution;

Usually the parent process needs to call the wait function family to wait for the child process to terminate, avoiding the child process becoming a zombie process. The resources in the thread to ensure that the terminated threads are available to the process, that is, to reclaim the resources that terminate the thread, should detach them at the end of each thread. A thread that is not separated will retain its virtual memory, including their stacks and other system resources, when terminated. Separating a thread means notifying the system that it no longer needs this thread, allowing the system to reclaim the resources it is assigned to.

Calling the Pthread_join function will automatically detach the specified thread, and the disconnected thread will no longer be able to be thread attached by another thread, which restores the system resources. If the thread is already in the detached state, calling Pthread_join will fail and will return EINVAL. So, if multiple threads need to know when a particular thread ends, those threads should wait for a condition variable instead of calling Pthread_join. All threads in a process can call the Pthread_join function to wait for other threads to terminate (that is, to reclaim system resources from other threads), the function's API is defined as follows:
/* Function: Wait for a thread to terminate; * return value: 0 If successful, return positive error code if error; * Function prototype: */#include <pthread.h>int pthread_join (pthread_t tid, void **s Tatus);/* Description: * All threads in a process can call this function to reclaim other threads, that is, wait for other threads to terminate; * The TID parameter is the identifier of the target thread, and the status parameter is the exit code that holds the target thread back; * The function blocks until the recovered thread terminates;

Each thread has its own thread ID, and the thread ID is returned by the function pthread_create that created the thread, which can use the function pthread_self to get its own thread ID, whose API is defined as follows:

/* Function: Gets its own thread ID; * Return value: Returns the thread ID of the calling thread; * Function prototype: */#include <pthread.h>pthread_t pthread_self (void);

A thread is either in a convergent state (the default) or out of state , and when a thread that is in a convergent state terminates, its thread ID and exit state are persisted to another thread to call Pthread_join. A disconnected thread is like a daemon, and when it terminates, all related resources are freed and we cannot wait for them to terminate. If one thread needs to know when another thread terminates, it is best to keep the second thread in a convergent state.

Call the Pthread_detach function to turn the specified thread out of state. It is defined as follows:

/* Function: Turn the specified thread into a detached state; * Return value: Returns 0 if successful, and returns a positive error code if an error occurs; * Function prototype: */#include <pthread.h>int pthread_detach (pthread_t tid);

All threads in the same process can call the Pthread_cancel function to cancel other threads to the request, and the thread that is requested to cancel can choose to allow cancellation or how to cancel. Canceling a thread is equivalent to terminating the thread abnormally, which is defined as follows:

/* Function: Request to cancel other threads of the same process; * return value: Returns 0 if successful, and returns a positive error code if the error occurs; * Function prototype: */#include <pthread.h>int pthread_cancel (pthread_t tid) ;/* Description: * The TID parameter is the identifier of the target thread; * Although a thread can be requested to cancel, the thread can decide whether to allow it to be canceled or how to cancel it, which is done by the following two functions: */#include <pthread.h>int pthread_ setcancelstate (int state, int *oldstate), int pthread_setcanceltype (int type, int *oldtype);/* Description: * The first parameter in these two functions is to set the cancellation state (that is, whether to allow cancellation) and the type of cancellation (that is, how to cancel), and the second parameter is to record the original cancellation and cancellation type of the thread, respectively; * State has two optional values: * 1, pthread_cancel_enable     allow the thread to be canceled (by default); * 2, pthread_cancel_disable    prohibit thread is canceled, in this case, if a thread receives a cancellation request, it will suspend the request until the thread is allowed to be canceled; * The type also has two selectable values: * 1, pthread_cancel_asynchronous   thread can be canceled at any time; * 2, pthread_cancel_deferred       allow the target thread to postpone execution;

Thread Properties

In the thread operation described earlier, the thread's default property process action is used. When creating a new thread, we can use the default properties of the system, or we can specify the main properties of the thread ourselves. We can specify the pthread_attr_t structure to modify the default properties of the thread and associate this property with the create thread. Let's look at the main properties of the thread:

/* struct definition */#include <bits/pthreadtypes.h> #define __sizeof_pthread_attr_t 36typedef union{    Char __size[__ sizeof_pthread_attr_t];    long int __align;} pthread_attr_t;

Thread properties mainly include the following four properties:

/  * * Thread's main properties:  * (1) detachstate     thread's out-of-state attribute;  * (2) guardsize       buffer Size (bytes) at the end of the thread stack;  (3)       the lowest address of the stackaddr line stacks;  * (4)       the size of the stacks of the StackSize Line (bytes);  

You must initialize a thread property operation before it is performed, and the initialization function is defined as follows:

/* Function: Initialize attribute structure; * Return value: Returns 0 if successful, otherwise returns an error code; * Function Prototype: */#include <pthread.h>/* Initialize Thread Property object */int pthread_attr_init (Pthre ad_attr_t *attr);/* If the thread property is dynamically allocated memory, the function must be called to destroy the Thread Property object */int Pthread_attr_destroy (pthread_attr_t *attr) before releasing memory;

Out-of- state properties

We can modify the thread out-of-state property detachstate through the pthread_attr_t structure, which is about the function of the property operation:

/* Function: Modify the Detach state property of the thread; * Return value: Returns 0 if successful, otherwise returns an error code; * Function Prototype: */#include <pthread.h>int pthread_attr_getdetachstate ( Const pthread_attr_t *attr, int *detachstate);//Gets the detach state property of the current thread; int pthread_attr_setdetachstate (pthread_attr_t *attr, int detachstate);//Set the Detach State property of the current thread;/* Description: * Detachstate value is the following two kinds: * (1) pthread_create_detached start thread in separate state; * (2) Pthread_ create_joinable normal boot thread (by default, the convergence state); */

Stack Properties

You can get or modify the stack properties of a thread by using the following action function.

/* Function: Gets or modifies the thread's stack properties; * Return value: Returns 0 if successful, otherwise returns an error encoding; * Function prototype: */#include <pthread.h>int pthread_attr_getstack (const pthread_attr_t *attr, void * * stackaddr, size_t stacksize);//get thread stack information; int Pthread_attr_setstack (pthread_attr_t *attr, void *stackaddr, size_t stacksize);//modify thread stack information; int pthread_attr_getstackaddr (const pthread_attr_t *attr, void * * STACKADDR);//Get thread stack start address information, int pthread_attr_setstackaddr (pthread_attr_t *attr, void *stackaddr);//Modify thread stack start address information; int Pthread_attr_getstacksize (const pthread_attr_t *attr, size_t *stacksize);//Get stack size information; int Pthread_attr_setstacksize ( pthread_attr_t *attr, size_t stacksize);//set stack size; int pthread_attr_getguardsize (const pthread_attr_t *attr, size_t * guardsize); int pthread_attr_setguardsize (pthread_attr_t *attr, size_t guardsize);

Mutual exclusion Lock

When multiple control threads share the same memory, you need to ensure that each thread sees a consistent view of the data. When multiple threads access modifiable variables, there is a consistency problem with the variables, which involves thread synchronization.

A mutex is also known as a mutex. You can protect data by using a mutually exclusive interface with pthread, ensuring that only one thread accesses the data at the same time. The mutex is essentially a lock that locks the mutex before accessing the shared resource, releasing the lock on the mutex after the access is complete. When the mutex is locked, any other thread that attempts to lock the mutex again will be blocked until the current thread releases the mutex. If multiple threads are blocked when a mutex is released, all blocked threads in the mutex become running, the first thread that becomes running can lock the mutex, and the other threads will see the mutex locked and can only go back and wait for it to become available again. In this way, only one thread can execute forward at a time.

The mutex is represented by the pthread_mutex_t data type, which must be initialized before the mutex is used, can be set to a constant Pthread_mutex_initializer (only for statically allocated mutexes), or it can be called pthread The _mutex_init function is initialized. If the mutex is allocated dynamically, the Pthread_mutex_destroy needs to be called before the memory can be freed.

/* Mutex *//* * Function function: Initialize mutual exclusion variable; * Return value: Returns 0 if successful, otherwise returns an error code; * Function Prototype: */#include <pthread.h>/* initialize mutex */int pthread_mutex_init (pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);/* Destroy mutexes, release system resources */int Pthread_mutex_destroy (pthread_mutex_t *MUTEX);/* * Description: * attr represents the property of the mutex, if attr is null, the initial mutex is the default property, *//* * function: To add and unlock the mutex; * return value: Returns 0 if successful, otherwise returns an error code; * Function prototype: */int PT Hread_mutex_lock (pthread_mutex_t *mutex);//Lock the mutex, the thread is blocked; int Pthread_mutex_trylock (pthread_mutex_t *mutex);// Lock the mutex, but the thread does not block; int Pthread_mutex_unlock (pthread_mutex_t *mutex);//unlock the Mutex;/* Description: * Call Pthread_mutex_lock to lock the mutex, If the mutex is locked, the calling thread is blocked until the mutex is unlocked; * Call Pthread_mutex_unlock to unlock the mutex, * call Pthread_mutex_trylock to lock the mutex, do not block, otherwise lock fails, Returns EBUSY. */

Mutex Properties

        Mutex properties can be manipulated with the pthread_mutexattr_t data structure, and the initialization of the properties is as follows:

/* Mutex attribute *//* * Function function: Initialize mutex attribute; * Return value: Returns 0 if successful, otherwise returns an error code; * Function Prototype: */#include <pthread.h>int pthread_mutexattr_init (PTH read_mutexattr_t *attr); int Pthread_mutexattr_destroy (pthread_mutexattr_t *attr);/* * Description: * pthread_mutexattr_ The init function initializes the pthread_mutexattr_t structure with the default mutex property; * Two attributes are process shared properties and type properties; *//* * Function function: Gets or modifies process share properties; * Return value: Returns 0 if successful, otherwise returns an error code; * Function prototype: */ #include <pthread.h>int pthread_mutexattr_getpshared (const pthread_mutexattr_t *attr, int *pshared);// Gets the mutex of the process share property int pthread_mutexattr_setpshared (pthread_mutexattr_t *attr, int pshared);//Set Mutex process share property/* Description: * When the process share mutex property is set to Pthread_process_private, the Pthread line libraries is allowed to provide a more efficient mutex implementation, which is the default in multithreaded applications, where multiple mutexes are shared by several processes. Pthread line libraries can limit the cost of a large mutex implementation; * If set to Pthread_process_private, the mutex can only be shared by the thread that is part of the same process as the lock initialization thread; *//* * Function function: Gets or modifies the Type property; Return value: Returns 0 if successful, otherwise returns an error code; * Function prototype: */int pthread_mutexattr_gettype (const pthread_mutexattr_t *attr, int *type);// Gets the type attribute of the mutex int pthread_mutexattr_settype (pthread_mutexattr_t *attr, int type);//Modify the Mutex Type property/* Description: * Type value is as follows: * 1, PThread_mutex_normal normal Lock (default) * 2, Pthread_mutex_errorcheck check the wrong lock * 3, pthread_mutex_recusive nested lock * 4, Pthre Ad_mutex_default Default Lock */

Mutex lock type:
    1. normal lock : When a thread locks on a normal lock, the remaining thread that requests the lock will form a wait queue and get it by priority after the lock has been unlocked. This kind of lock can trigger a deadlock, that is, when the same thread locks an already locked normal lock again, a deadlock is raised.
    2. error-checking lock : When a Chengjo lock is added again to a locked lock, the lock operation returns EDEADLK, unlocks a check lock that has been Cheng by another line, or unlocks an unlocked check lock again, the unlock operation returns EPERM.
    3. nested locks : This type of lock allows a thread to lock a lock multiple times before releasing it without deadlock. However, for other threads to obtain the lock, the owner of the current lock must perform an appropriate number of unlocking operations. The unlock operation returns eperm for a nested lock that has been Cheng by another thread, or for unlocking a nested lock that has already been unlocked.
    4. default lock : A line Chengjo locks a locked default lock again, or unlocks a default lock that has been Cheng by another line, or unlocks a default lock that has been unlocked again, causing unintended consequences. The implementation of this lock may be mapped to one of the three types of locks above.
condition Variable

Mutexes are used to synchronize the access of a thread to shared data, which is the value used to synchronize shared data between threads. Mutexes provide a mutually exclusive access mechanism, which provides a signaling mechanism that wakes a thread waiting for the shared data when a shared data reaches a certain value. A condition variable can enter one or more threads into a blocking state until a notification from another thread is received, or a timeout occurs, or a false wake is taken to exit the blocking state.

The condition variable is used in conjunction with the mutex, allowing the thread to wait for a particular condition to occur in a non-competitive manner, and the condition itself is protected by a mutex. The thread must lock the mutex before changing the condition state, and the condition variable allows the thread to wait for a specific condition to occur. Conditional variables compensate for the lack of mutexes by allowing threads to block and wait for another thread to send a signal, which is often used in conjunction with mutexes. When used, a condition variable is used to block a thread, and when the condition is not met, the thread often unlocks the corresponding mutex and waits for the condition to change. Once another thread changes the condition variable, it notifies the corresponding condition variable to wake one or more threads that are being blocked by this condition variable. These threads will re-lock the mutex and re-test whether the condition is satisfied. In general, conditional variables are used for synchronization between threads. The condition variable type is pthread_cond_t and must be initialized before it is used. There can be two types of initialization: Assigning a constant Pthread_cond_initializer to a statically assigned condition variable, and using Pthread_cond_init to initialize a dynamically assigned condition variable. The operation functions are as follows:

/* condition variable *//* * function function: Initialize condition variable; * Return value: Returns 0 if successful, otherwise returns error code; * Function Prototype: */#include <pthread.h>int pthread_cond_init (pthread_cond_t *cond, pthread_condattr_t *attr); int Pthread_cond_destroy (pthread_cond_t *cond);/* Description: * Cond parameter points to the target condition variable to be manipulated, attr parameter specifies the property of the condition variable *//* * Function: Wait for the condition variable to become true; * Return value: Returns 0 if successful, otherwise returns an error code; * Function prototype: */int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mu  Tex); int pthread_cond_timewait (pthread_cond_t *cond, pthread_mutex_t *mutex, const struct TIMESPEC *timeout);/* * Description: * The mutex passed to the pthread_cond_wait protects the condition, the caller passes the locked mutex to the function, and the function places the calling thread on the list of threads waiting for the condition, and then unlocks the mutex, both of which are atomic operations; This turns off the time channel between the condition check and the thread going into hibernation waiting for the condition to change, so that the condition changes are not missed; * Pthread_cond_wait returns, the mutex is locked again; *//* * Function: The thread that wakes the waiting condition; Return value: Returns 0 if successful, otherwise returns an error code; * Function prototype: */int pthread_cond_signal (pthread_cond_t *cond);//Wake up a thread waiting for the condition, specifically wake up which thread depends on the thread's priority and scheduling policy ; int Pthread_cond_broadcast (pthread_cond_t *cond);//Wake Up all threads waiting for the condition; 

condition Variable Properties

The condition variable also has only the process share property, which operates as follows:

/* Condition Variable Property *//* * Function function: Initialize condition variable property; * Return value: Returns 0 if successful, otherwise returns an error code; * Function Prototype: */#include <pthread.h>int pthread_condattr_init (PT hread_condattr_t *attr); int Pthread_condattr_destroy (pthread_condattr_t *attr);/* Function function: Gets or modifies the process share property; * Return value: 0 if successful Otherwise, the error code is returned; * Function prototype: */#include <pthread.h>int pthread_condattr_getpshared (const pthread_condattr_t *attr, int * pshared); int pthread_condattr_setpshared (pthread_condattr_t *attr, int pshared);

Threads and Signals

When a thread is created, it inherits the signal mask of the process, and the mask becomes thread-private, so each thread can set the signal mask independently. All threads in a process are signals that the process is shared. Multiple threads are the address space of a shared process, and each thread has the same handler function for the signal, that is, if a thread modifies a handler function associated with a signal, all threads in the process must share the change in the handler. That is, when a signal handler for a signal is set on a thread, it overrides the signal processing function set by the other thread for the same signal.

Each signal is only passed to a thread, that is, the signal in the process is passed to a single thread, and the thread passed to it is indeterminate. If the signal is related to a hardware failure or timer timeout, the signal is sent to the thread that caused the event. However, the alarm timer is a resource shared by all threads, so the simultaneous use of alarm in multiple threads can interfere with each other.

The sigprocmask can be called in the process to prevent the signal from being sent, but in a multithreaded process its behavior is undefined and it can do nothing. Calling Pthread_sigmask in the main thread causes all threads to block a signal, or it can be called in a thread to set its own mask.

/* thread and signal *//* * Function function: Set the signal screen word of the thread; * Return value: Returns 0 if successful, otherwise returns an error code; * Function Prototype: */#include <signal.h>int pthread_sigmask (int how, C Onst sigset_t *set, sigset_t *oset); */* Description: * This function is basically the same function as the one previously described in the process to set the signal screen character sigprocmask; *//* * Function: Wait for a signal or more to occur; * Return value: Returns 0 if successful, otherwise returns an error code; * Function prototype: */int sigwait (const sigset_t *set, int *signop);/* Description: * The Set parameter indicates the set of signals that the thread waits for, and the integer that the Signop points to is the return value indicating that the The number of signals sent; *//* * function: Send a signal to the thread; * Return value: Returns 0 if successful, otherwise returns an error code; * Function prototype: */int Pthread_kill (pthread_t thread, int signo);/* * Description: * si Gno can be a check thread exists, if the signal's default processing action is to terminate the entire process, then the signal to a thread will still kill the entire process;

If a signal in the signal set is in a pending state at the time of the sigwait call, the sigwait will immediately return without blocking, and sigwait will remove the signals from the process that are in the pending state before returning. To avoid the error action, the thread must block the signal it is waiting for before calling Sigwait. The sigwait function automatically cancels the blocking state of the signal set until the new signal is delivered. Before returning, sigwait will restore the thread's signal screen word
Threads and Processes

When a multithreaded parent process calls the fork function to create a child process, the child process inherits a copy of the entire address space. There is only one thread in the child process, which is a copy of the thread that called the fork function in the parent process. Threads in a child process inherit the same state in the parent process, which has the same mutex and condition variables. If a thread in the parent process occupies a lock, the child process also occupies those locks, except that the child process does not contain a copy of the thread that holds the lock, so it is not aware of which locks are occupied and which locks need to be freed.

If the EXEC function is not called immediately after the child process returns from the fork, the fork handler cleanup lock state needs to be called. You can call the Pthread_atfork function to implement the cleanup lock state:

/* Thread and fork *//* * Function function: clean lock status; * Return value: Returns 0 if successful, otherwise returns an error code; * Function Prototype: */#include <pthread.h>int pthread_atfork (void (*prepa RE) (void), void (*parent) (void), void (*child) (void));/* Description: * This function can install up to three functions to help clean up the lock; * Prepare fork handler is called by the parent process before the fork creates the child process , the task of this fork handler is to get all the locks defined by the parent process; * * The parent fork handler is called after the fork creates the child process, but before the fork is returned in the parent process environment, the task of the fork handler is to the Prepare fork handler * Gets all locks unlocked; * * The Child fork handler is called in the sub-process environment before the fork is returned, and, like the parent fork handler, must free all locks obtained by the prepare fork handler; */

Resources:

"Unix Network Programming"

Network Programming thread

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.