[Linux] Connect terminated threads (pthread_join), thread detachment (pthread_detach), thread cancellation (pthread_detach)

orange color

1. Connect the terminated thread (pthread_join)

Function analysis

/*
    #include <pthread.h>
    int pthread_join(pthread_t thread, void **retval);
        - 功能:和一个已经终止的线程进行连接,从而回收子线程的资源
                这个函数是阻塞函数,调用一次只能回收一个子线程
                一般在主线程中使用
        - 参数:
            - thread:需要回收的子线程的ID
            - retval: 接收子线程退出时的返回值
        - 返回值:
            0 : 成功
            非0 : 失败,返回的错误号
*/

Code example

#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>

int value = 10;

void * callback(void * arg) {
    
    
    printf("child thread id : %ld\n", pthread_self());
    // sleep(3);
    // return NULL; 
    // int value = 10; // 局部变量,在一个进程中不同的线程划分了不同的栈空间,当子线程结束后属于子线程的栈空间就被释放掉了。
    //所以后面主线程中就没办法通过pthread_join来接收子线程的返回值。所以想要接收,value必须为全局变量(不能是局部变量)
    pthread_exit((void *)&value);   // return (void *)&value;
} 

int main() {
    
    

    // 创建一个子线程
    pthread_t tid;
    int ret = pthread_create(&tid, NULL, callback, NULL);

    if(ret != 0) {
    
    
        char * errstr = strerror(ret);
        printf("error : %s\n", errstr);
    }

    // 主线程
    for(int i = 0; i < 5; i++) {
    
    
        printf("%d\n", i);
    }

    printf("tid : %ld, main thread id : %ld\n", tid ,pthread_self());

    // 主线程调用pthread_join()回收子线程的资源,通过thread_retval来接收子线程退出时的返回值
    //注意,如果子线程没有结束,则主线程会一直阻塞在这里等待回收
    int * thread_retval;
    ret = pthread_join(tid, (void **)&thread_retval);

    if(ret != 0) {
    
    
        char * errstr = strerror(ret);
        printf("error : %s\n", errstr);
    }

    printf("子线程返回值 : %d\n", *thread_retval);

    printf("回收子线程资源成功!\n");

    // 让主线程退出,当主线程退出时,不会影响其他正常运行的线程。
    pthread_exit(NULL);

    return 0; 
}

Insert image description here

An explanation of why pthread_join(tid, (void **)&thread_retval) in the program passes in a secondary pointer. Assume that the address of value (value 10) is 0x0001, then I defined it through int * thread_retval in the main program A first-level pointer, I need to modify the value of this first-level pointer to make it 0x0001. So I passed it into the pthread_join function. I must pass in the address of the first-level pointer (that is, the second-level pointer) before I can change the value of the first-level pointer to 0x0001 within the function. If you just pass the first-level pointer in, its value will change within the function, but it will still not change outside the function.
For example, if I int a and want to change its value through a function, then the value passed in should be &a, so that will work.

2. Separation of threads

Function analysis

/*
    #include <pthread.h>
    int pthread_detach(pthread_t thread);
        - 功能:分离一个线程。被分离的线程在终止的时候,会自动释放资源返回给系统。
          1.不能多次分离,会产生不可预料的行为。
          2.不能去连接一个已经分离的线程,会报错。
        - 参数:需要分离的线程的ID
        - 返回值:
            成功:0
            失败:返回错误号
*/

Code example

#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>

void * callback(void * arg) {
    
    
    printf("chid thread id : %ld\n", pthread_self());
    return NULL;
}

int main() {
    
    

    // 创建一个子线程
    pthread_t tid;

    int ret = pthread_create(&tid, NULL, callback, NULL);
    if(ret != 0) {
    
    
        char * errstr = strerror(ret);
        printf("error1 : %s\n", errstr);
    }

    // 输出主线程和子线程的id
    printf("tid : %ld, main thread id : %ld\n", tid, pthread_self());

    // 设置子线程分离,子线程分离后,子线程结束时对应的资源就不需要主线程释放
    ret = pthread_detach(tid);
    if(ret != 0) {
    
    
        char * errstr = strerror(ret);
        printf("error2 : %s\n", errstr);
    }

    // 设置分离后,对分离的子线程进行连接 pthread_join()
    // ret = pthread_join(tid, NULL);
    // if(ret != 0) {
    
    
    //     char * errstr = strerror(ret);
    //     printf("error3 : %s\n", errstr);
    // }

    pthread_exit(NULL);

    return 0;
}

The main thread creates a child thread. The default attribute of the thread is the non-detached state. The main thread waits for the child thread to end. Only when the pthread_join() function returns, the created child thread is terminated and the system resources it occupies can be released. The detached state means that the thread is not waiting for other threads. After it finishes running, the thread ends and system resources are released immediately.
My understanding is that if the thread ends first and then runs to the pthread_detach() function, this function will also work, because after the thread has finished running, it does not mean that the resources have been released. If the pthread_join() function is not called, it needs to become a detached state to release resources.

3. Thread cancellation

Function analysis

/*
    #include <pthread.h>
    int pthread_cancel(pthread_t thread);
        - 功能:取消线程(让线程终止)
            取消某个线程,可以终止某个线程的运行,
            但是并不是立马终止,而是当子线程执行到一个取消点,线程才会终止。
            取消点:系统规定好的一些系统调用,我们可以粗略的理解为从用户区到内核区的切换,这个位置称之为取消点。
        - 应用:比如说清理垃圾,会开启一个线程去执行,中途你不想清理了,点击取消,就终止线程了
*/

Code example

#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>

void * callback(void * arg) {
    
    
    printf("chid thread id : %ld\n", pthread_self());
    for(int i = 0; i < 5; i++) {
    
    
        printf("child : %d\n", i);
    }
    return NULL;
}

int main() {
    
    
    
    // 创建一个子线程
    pthread_t tid;

    int ret = pthread_create(&tid, NULL, callback, NULL);
    if(ret != 0) {
    
    
        char * errstr = strerror(ret);
        printf("error1 : %s\n", errstr);
    }

    // 取消线程
    pthread_cancel(tid);

    for(int i = 0; i < 5; i++) {
    
    
        printf("%d\n", i);
    }

    // 输出主线程和子线程的id
    printf("tid : %ld, main thread id : %ld\n", tid, pthread_self());

    
    pthread_exit(NULL);

    return 0;
}

Insert image description here

As can be seen from the results, 主函数执行完了所有的内容,最后子线程仅执行了printf,并没有执行for循环下的printf。this means that printf under the for loop is a system-specified cancellation point (note that pthread_cancel is a non-blocking function, so after calling this function, even if the child thread has not terminated, the main thread can still continue run down)

而且每次运行,结果可能是不同的

4. Thread attributes

The main function is also to set thread separation, but the function is different from the above. and some other functions to obtain thread-related properties.

Function analysis

/*
    int pthread_attr_init(pthread_attr_t *attr);
        - 初始化线程属性变量

    int pthread_attr_destroy(pthread_attr_t *attr);
        - 释放线程属性的资源

    int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);
        - 获取线程分离的状态属性

    int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
        - 设置线程分离的状态属性
*/ 

Code example

#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>

void * callback(void * arg) {
    
    
    printf("chid thread id : %ld\n", pthread_self());
    return NULL;
}

int main() {
    
    

    // 创建一个线程属性变量
    pthread_attr_t attr;
    // 初始化属性变量
    pthread_attr_init(&attr);

    // 设置属性,PTHREAD_CREATE_DETACHED 代表线程分离
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    // 创建一个子线程
    pthread_t tid;

    int ret = pthread_create(&tid, &attr, callback, NULL);
    if(ret != 0) {
    
    
        char * errstr = strerror(ret);
        printf("error1 : %s\n", errstr);
    }

    // 获取线程的栈的大小
    size_t size;
    pthread_attr_getstacksize(&attr, &size);
    printf("thread stack size : %ld\n", size);

    // 输出主线程和子线程的id
    printf("tid : %ld, main thread id : %ld\n", tid, pthread_self());

    // 释放线程属性资源
    pthread_attr_destroy(&attr);

    pthread_exit(NULL);

    return 0;
}

Insert image description here

Guess you like

Origin blog.csdn.net/mhyasadj/article/details/130922121