Unix environment variables-advanced thread programming

One, thread private data

All threads in a process share the data space of the process, so global variables are shared by all threads. In some scenarios, the thread needs to save its own private data. At this time, you can create a thread-specific data (Thread-specific Data) TSD to solve it. Inside the thread, private data can be accessed by various interfaces of the thread, but shielded from other threads

int pthread_key_create(pthread_key_t *key, void (*destr_function) (void*));//创建键

Parameters: key: store the applied key value

destr_function: When the thread exits after execution, the value pointed to by key is used as an input parameter to call

int pthread_setspecific(pthread_key_t key, const void *pointer);//Set thread private data for the specified key value

void * pthread_getspecific(pthread_key_t key);//Read thread private data from the specified key

void * pthread_getspecific(pthread_key_t key);//Delete a key, do not delete the data at this time


Second, the cancellation point of the thread

There are two other attributes of the thread that are not included in the thread attributes, that is, the cancelable state and the cancelable type of the thread. As mentioned earlier, the pthread_cancel() function only requests the specified thread to exit, but whether the thread will exit immediately depends on its cancelable state and cancelable type or whether it reaches the thread's cancelable point (cancelable point refers to the program running To a system call with a cancellation point).

int pthread_setcancelstate(int newstate,int* oldstate);

Function: Set the cancelable state of the thread to newstate, and save the previous state in oldstate.

There are two values: PTHREAD_CANCEL_ENABLE, PTHREAD_CANCEL_DISABLE

Another situation is that when our request is successfully sent, but because the thread has been busy, it never enters the system call containing the cancellation point. At this time, we can actively set a cancellation point through the following function.

void pthread_testcancel(void)

int pthread_setcanceltype(int type,int* oldtype);//Set the cancelable type of the thread

There are two types of values: PTHREAD_CANCEL_ASYNCHRONOUS (asynchronous cancellation), PTHREAD_CANCEL_DEFERRED (delayed cancellation)

Asynchronous cancellation can be responded at any time.


Three, multi-threading and signals

In a multithreaded environment, the generated signal is passed to the entire process. Generally speaking, all threads have a chance to receive this signal.

If it is a signal generated by an exception (such as a program error, such as SIGPIPE, SIGEGV), only the thread that generated the exception will receive and process it.

If it is a signal generated by an external kill command, usually a job control signal such as SIGINT, SIGHUP, etc., it will traverse all threads until it finds a thread that does not block the signal, and then calls it to process it. (Usually found from the main thread), note that only one thread can receive.

By default, the signal will be received and processed by the main process, even if the signal processing function is registered by the child thread, unless the main thread shields the signal, each thread has its own signal shielding set (signal mask), which can be shielded using the pthread_sigmask function A thread responds to certain signals, leaving only the thread that needs to process the signal to process the specified signal. The implementation method is: use the inheritance relationship of the thread signal shielding set (after setting the sigmask in the main process, the thread created by the main process will inherit the mask of the main process).

 In multithreaded code, functions such as sigwait or sigwaitinfo or sigtimedwait are always used to process signals. Rather than functions such as signal or sigaction. Because calling functions such as signal or sigaction in one thread will change the signal processing functions in all threads. Instead of just changing the signal processing function of the thread that calls signal/sigaction.

int pthread_sigwait(const sigset_t *set, int *sig);//Thread synchronization waiting for the arrival of the signal

int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset);//Set the signal mask set of the thread

In a multithreaded program, a thread can use pthread_kill to send a signal to a specified thread (including itself) in the same process. Note that in multithreading, the kill function is generally not used to send signals, because kill sends signals to the process. The result is: the running thread will process the signal. If the thread does not register the signal processing function, it will cause the entire process to exit.

int pthread_kill(pthread_t thread, int sig);//Send a signal to the specified thread


Fourth, fork() and multithreading

In the case of multi-threaded running, calling the fork() function will only copy the calling thread to the child process. But the state of global variables and all pthreads objects (such as mutually exclusive variables, condition variables, etc.) will be retained in the child process, which creates a critical situation. For example: a thread locks a mutually exclusive amount before fork() is called, and updates a global variable in half, at this time fork() is called, and all data and state are copied to the child process , Then the mutually exclusive quantity cannot be unlocked in the child process (because it is not the owner of the mutually exclusive quantity), assuming that another attempt to lock the mutually exclusive quantity will lead to deadlock. So after fork(), the child process cannot call:

(1) malloc: Because malloc() locks when accessing the global state.

(2) No matter what function may allocate or release memory, including new, map::insert(), snprintf()...

(3) No matter what pthreads function. You cannot use pthread_cond_signal() to notify the parent process, you can only synchronize by reading and writing pipe(2).

(4) The printf() series of functions, because other threads may happen to hold the stdout/stderr lock.

No matter what function except the "signal safe" function clearly listed in man 7 signal.

Therefore, it is recommended to call fork() in a multi-threaded program only if you call the exec() function immediately afterwards to completely isolate the relationship between the child process and the parent process. The new process overwrites the original memory, making all pthreads objects in the child process disappear.

 int pthread_atfork (void (*prepare) (void), void (*parent) (void), void (*child) (void));

Parameters: prepare: is called before the new process is created

parent: is called in the parent process after the new process is created

child: After the new process is created, the child process is called

Guess you like

Origin blog.csdn.net/Chiang2018/article/details/105418684
Recommended