Advanced Programming for UNIX Environment Notes - Identification, Creation and Termination of Threads

Posted by beckstei on Wed, 24 Jul 2019 22:51:45 +0200

Original Link: http://www.cnblogs.com/riasky/p/3507639.html

1. Thread identification

Just as each process has a process ID, each thread has a thread ID.The process ID is unique throughout the system, but the thread ID is only in which it belongs
Valid in a process environment.
Thread ID s are represented by the pthread_t data type and can be implemented using a structure to represent the pthread_t data type, so the portable operating system
The implementation cannot compare it to integer processing.A function must therefore be used to compare thread ID s.
#include <pthread.h>
int pthread_equal(pthread_t tid1, pthread_t tid2); //If equal returns a non-zero value, otherwise 0 is returned.
Threads can obtain their own thread ID by calling the pthread_self function.
#include<pthread.h>
pthread_t pthread_self(void); //The return value is the thread ID of the calling thread.

2. Thread Creation

In the traditional UNIX process model, each process has only one control thread, which is conceptually equivalent to having only one thread per process in the thread-based model
It's the same.In the case of POSIX threads, when the program starts running, it is also started by a single control thread in a single process, creating multiple
Before controlling threads, the program behaved no differently from traditional processes; new threads can be created by calling the pthread_create function.
#include<pthread.h>
int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void*), void*restrict arg );
//Return 0 if successful, otherwise return error number
When pthread_create returns successfully, the memory unit pointed to by tidp is set to the thread ID of the newly created thread, and the attr parameter is used to customize various threads
Properties.The newly created thread runs from the address of the start_rtn function, which has only one untyped pointer parameter, arg, if it needs to be passed to the start_rtn function
There is more than one parameter, which needs to be put into a structure and passed in as an arg parameter.
Thread creation does not guarantee which thread will run first. Newly created threads can access the process's address space and inherit floating-point environments and letters from call points
No. masks the word, but the thread's pending semaphore set is cleared.
Be careful:
pthread functions usually return error codes after a call fails, and they do not set errno like other POSIX functions, so strerror functions are often used to
Error codes are translated into descriptive information rather than errno directly using the perror function.

3. Thread termination

If any thread in the process calls exit, _Exit, or _exit, the entire process terminates.If the default action of the signal is to terminate the process, set the
Signaling to a thread terminates the entire process.
A thread can exit in three ways to stop its control flow without terminating the entire process.
1. Threads are simply returned from the startup routine, and the return value is the thread's exit code.
2. Threads can be cancelled by other threads in the same process.
3. Thread calls pthread_exit.
	#include<pthread.h>
	void pthread_exit(void *rval_ptr);
rval_ptr is an untyped pointer, and with a single parameter type passed to the startup routine, other threads in the process can be accessed by calling the pthread_join function
To this pointer.
	#include <pthread.h>
	int pthread_join(pthread_t thread, void **rval_ptr); //Returns 0 if successful, otherwise returns the error number.
The calling thread will remain blocked until the specified thread calls pthread_exit, returns from the startup routine, or cancels.If a thread is only starting a routine from it
Return, rval_ptr will contain the return code.If the thread is cancelled, the content unit specified by rval_ptr is set to PTHREAD_CANCELED.
If you are not interested in the return value of a thread, you can set rval_ptr to NULL.

Practice:
#include <stdio.h>
#include <pthread.h>
#include <string.h>

void* thr_fn1(void *arg){
        printf("thread 1 return.\n");
        return (void*)1;
}

void* thr_fn2(void *arg){
        printf("thread 2 exit.\n");
        pthread_exit((void*)2);
}

int main(void){
        int err;
        pthread_t tid1,tid2;
        void* tret;

        err = pthread_create(&tid1, NULL, thr_fn1, NULL);
        if(err != 0){
				printf("pthread_create:%s\n",strerror(err));
                return -1;
        }

        err = pthread_create(&tid2, NULL, thr_fn2, NULL);
        if(err != 0){
                printf("pthread_create:%s\n",strerror(err));
                return -1;
        }

        err = pthread_join(tid1, &tret);
        if(err != 0){
                printf("pthread_join:%s\n",strerror(err));
                return -1;
        }
        printf("thread1 exit code %d\n",(int)tret);

        err = pthread_join(tid2, &tret);
        if(err != 0){
                printf("pthread_join:%s\n",strerror(err));
                return -1;
        }
        printf("thread1 exi2 code %d\n",(int)tret);

        return 0;
}
Compile:
Gcc-pthread thread.c UNIX is not multi-threaded natively, and multithreading is implemented through the pthread library, so it needs to be compiled using the pthread library.
Execution:
thread 2 exit.
thread 1 return.
thread1 exit code 1
thread1 exi2 code 2

The untyped pointer parameters of the pthread_create and pthread_exit functions can pass more than one parameter value, and the pointer can pass structs with more complex information
Address (which is why rval_ptr in pthread_join is of type double pointer), but the memory used by the structure must remain valid after the caller completes.
 
Threads can request cancellation of other threads in the same process by calling the pthread_cancel function.
	#include<pthread.h>
	int pthread_cancel(pthread_t itd); //Return 0 if successful, otherwise return error number
By default, the pthread_cancel function causes the thread identified by the tid to behave as if it had called pthread_exit with the parameter PTHREAD_CANCELED
Function, but threads can ignore or control the cancellation.
 
A thread can schedule the functions it needs to call when it exits, which are of type atexit functions for a process.Such a function is called a thread cleanup handler, and threads can create multiple
Clean handlers, which are recorded on the stack, that is, they execute in the reverse order as they were registered.
#include<pthread.h>
	void pthread_cleanup_push(void (*rtn)(void *), void* arg);
	void pthread_cleanup_pop(int execute);
The cleanup function is called when the thread performs the following actions, with the parameter arg. The call order of the cleanup function rtn is arranged by the pthread_clean_push function.
1. When pthread_exit is called.
2. In response to a cancellation request.
3. When pthread_cleanup_pop is called with a non-zero execute parameter.
If the execute parameter is set to zero, the cleanup function will not be called.pthread_cleanup_pop will delete the last time whether the execute parameter is 0 or not
pthread_cleanup_push calls the established cleanup handler.

The following points to note when using these two functions:
1.push and pop must appear in pairs.
2.push can have more than one, and pop can also have a corresponding number.

Practice:
#include <stdio.h>
#include <pthread.h>

void cleanup(void *arg){
        printf("cleanup:%s\n",(char*)arg);
}

void *thr_fn1(void *arg){
        printf("thread 1 start\n");
        pthread_cleanup_push(cleanup, "thread 1 first handler");
        pthread_cleanup_push(cleanup, "thread 1 second handler");
        printf("thread 1 push complete\n");
        return (void *)1;
        pthread_cleanup_pop(0);
        pthread_cleanup_pop(0);
}

void *thr_fn2(void *arg){
        printf("thread 2 start\n");
        pthread_cleanup_push(cleanup, "thread 2 first handler");
        pthread_cleanup_push(cleanup, "thread 2 second handler");
        printf("thread 2 push complete\n");
        pthread_exit((void *)2);
        pthread_cleanup_pop(0);
        pthread_cleanup_pop(0);
}

int main(void){
        pthread_t tid1,tid2;
        int err;
        void* tret;

        err = pthread_create(&tid1, NULL, thr_fn1, (void*)1);
        if(err != 0){
                printf("pthread_create:%s\n",strerror(err));
                return -1;
        }

        err = pthread_create(&tid2, NULL, thr_fn2, (void*)2);
        if(err != 0){
                printf("pthread_create:%s\n",strerror(err));
                return -1;
        }

        err = pthread_join(tid1,&tret);
        if(err != 0){
                printf("pthread_join:%s\n",strerror(err));
                return -1;
        }
        printf("thread 1 exit code:%d\n",(int)tret);

        err = pthread_join(tid2,&tret);
        if(err != 0){
                printf("pthread_join:%s\n",strerror(err));
                return -1;
        }
        printf("thread 2 exit code:%d\n",(int)tret);

        return 0;
}

You may have questions:
Didn't pthread_cleanup_pop in thr_fn1 and thr_fn2 fail to execute?Yes, but if you don't write, there will be syntax errors and the compilation will not pass.Because push and
pop must appear in pairs.

Run result:
thread 2 start
thread 2 push complete
cleanup:thread 2 second handler
cleanup:thread 2 first handler
thread 1 start
thread 1 push complete
thread 1 exit code:1
thread 2 exit code:2
As a result, the cleanup function can only be called after the pthread_exit function has been called.

You can now see that threads and process functions have many similarities.


By default, the thread termination state is saved until pthread_join is called on the thread, and if the thread is already detached, the underlying storage resources of the thread can be
The thread is retracted immediately upon termination.When a thread is detached, it is not possible to wait for its termination state with the pthread_join function to pthread_join the detached thread
The call fails and returns EINVAL.The pthread_detach call can be used to allow threads to enter a detached state.
#include <pthread.h>
int pthread_detach(pthread_t tid); //Success returns 1, otherwise the error number is returned.

Practice:
#include <stdio.h>
#include <pthread.h>
#include <string.h>

void *thr_fn(void *arg){
        printf("thread start\n");
        printf("thread complete\n");
        pthread_exit((void *)1);
}

int main(void){
        pthread_t tid1;
        int err;
        void* tret;

        err = pthread_create(&tid1, NULL, thr_fn, (void*)1);
        if(err != 0){
                printf("pthread_create:%s\n",err);
                return -1;
        }

        err = pthread_detach(tid1);
        if(err != 0){
                printf("pthread_detach:%s\n",err);
                return -1;
        }

        err = pthread_join(tid1,&tret);
        if(err != 0){
                printf("pthread_join:%s\n",strerror(err));
                return -1;
        }
        printf("thread 1 exit code:%d\n",(int)tret);
        return 0;
}

Run result:
pthread_join:Invalid argument
The termination state cannot be obtained because the thread is already in a detached state.

 

Reprinted at: https://www.cnblogs.com/riasky/p/3507639.html

Topics: Unix