【UNIX环境高级编程】线程_5_线程终止

目录

pthread_exit

pthread_join

pthread_cancel

pthread_cleanup_push、pthread_cleanup_pop

pthread_cleanup_push()

pthread_cleanup_pop()


单个线程可以通过下列三种方式退出,在不终止这个进程的情况下停止他的控制流。

  1. 线程只是从启动例程中返回,返回值是线程的退出码。
  2. 线程可以被同一进程中的其他线程取消。
  3. 线程调用 pthread_exit。
#include<pthread.h>
void pthread_exit(void *rval_ptr);

rval_ptr 参数是一个指向线程退出状态值的指针。它的主要作用是允许线程在终止时向其创建者(通常是调用 pthread_join() 的线程)传递一个值,进程中其他线程可以通过调用pthread_join函数访问到这个指针,然后通过这个指针获取退出状态。

pthread_exit

#include<pthread.h>
void pthread_exit(void *rval_ptr);

pthread_exit 是 POSIX 线程库中显式终止线程的方法,想要结束的线程自己调用该函数。并将通过 rval_ptr 传递退出时想传递的值。

pthread_join

#include<pthread.h>
int pthread_join(pthread_t thread, void **rval_ptr);

pthread_join() 主要用于 线程同步 和 资源回收。它的核心功能是阻塞当前线程,直到目标线程终止,并获取目标线程的退出状态。

在默认情况下,线程的终止状态会保存到对该线程调用 pthread_join,如果线程已经处于分离状态,线程底层存储资源可以在线程终止时立即被回收,当线程被分离时,并不能用 pthread_join 函数等待它的终止状态。对分离的线程调用 pthread_join 会失败,返回 EINVAL。

pthread_join() 中的 rval_ptr 参数用于去传递目标线程的退出值。

void *worker(void *arg) {
    int *result = malloc(sizeof(int));
    *result = 42;
    pthread_exit(result);  // 传递退出状态
}

int main() {
    pthread_t tid;
    void *retval;
    
    pthread_create(&tid, NULL, worker, NULL);
    pthread_join(tid, &retval);  // 阻塞等待
    
    if (retval != NULL) {
        printf("Result: %d\n", *(int*)retval);
        free(retval);  // 必须手动释放
    }
}

运行结果:42

pthread_cancel

#include<pthread.h>
int pthread_cancel(pthread_t tid);    //成功返回0,失败返回错误编号

pthread_cancel()  函数会使 tid 标识的线程如同调用了 PTHREAD_CANCELED 的 pthread_exit() 函数。这里要注意的是,pthread_cancel 并不等待线程终止,它仅仅提出请求,线程可以选择忽略取消方式或是控制取消方式。

pthread_cleanup_push、pthread_cleanup_pop

#include<pthread.h>
void pthread_cleanup_push(void (*rtn)(void*),void *arg);
void pthread_cleanup_pop(int execute);

线程可以在退出时调用想要调用的函数,主要用于在线程终止时自动释放资源(如锁、文件描述符等),这样的函数称为线程清理处理程序。线程可以建立多个清理处理程序。处理程序记录在栈中,也就是说它们的执行顺序与它们注册时的顺序相反。

pthread_cleanup_push()

将清理函数 rtn 压入线程的清理栈中,并绑定参数arg。清理函数会在以下情况被调用:

  • 线程调用 pthread_exit() 显示终止
  • 线程被其他线程取消(pthread_cancel)
  • 调用 pthread_cleanup_pop(1) 主动触发

pthread_cleanup_pop()

将清理栈中弹出函数,并根据参数 execute 决定是否执行:

  • execute != 0:执行清理函数
  • execute == 0:仅弹出不执行

下面用一个例子来解释一下,例子是用于线程结束后调用清理函数自动释放内存。

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

/* 清理函数:释放内存 */
void cleanup(void *arg) {
    printf("执行清理:释放内存 %p\n", arg);
    free(arg);
}

void *thread_func(void *arg) {
    int *data = malloc(sizeof(int));
    *data = 42;
    printf("线程分配内存: %p (值=%d)\n", data, *data);

    /* 注册清理函数 */
    pthread_cleanup_push(cleanup, data);

    /* 模拟线程可能被取消的操作 */
    if (1) {  // 这里设为1只是为了演示,实际应该有条件判断
        printf("线程调用pthread_exit退出\n");
        pthread_exit(NULL);  // 这会触发清理函数
    }

    /* 必须成对出现(实际不会执行到这里) */
    pthread_cleanup_pop(0);  // 0表示不执行清理(因为前面已经通过pthread_exit触发了)
    return NULL;
}

int main() {
    pthread_t tid;
    pthread_create(&tid, NULL, thread_func, NULL);
    pthread_join(tid, NULL);
    printf("主线程结束\n");
    return 0;
}

运行结果:线程分配内存: 0x7f8babc00000 (值=42)
                  线程调用pthread_exit退出
                  执行清理:释放内存 0x7f8babc00000
                  主线程结束

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值