Linux线程终止

当进程中的某一个线程调用了exit、_Exit、_exit,那么整个进程会终止。同样,一个信号发送到某个线程,而该信号的默认动作是终止,整个进程也会终止。

单个进程的终止有三种方法:

  • 从程序正常返回。
  • 线程自身调用pthread_exit。
  • 被同一进程中的其它线程取消。

先来看看前两种情况。

void pthread_exit(void *rval_ptr);     // 退出线程,可通过参数向其它线程传递信息
int pthread_join(pthread_t thread, void **rvalptr);     // 阻塞等待指定线程退出,可获得线程退出时的信息

注意,pthread_join所等待的线程可以以上述三种方式退出,**rvalptr都能获得退出信息。下面是两个函数的测试例程:

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

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

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

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

    pthread_create(&tid1, NULL, thr_fn1, NULL);
    pthread_create(&tid2, NULL, thr_fn2, NULL);

    pthread_join(tid1, &ret);  // 等待线程1退出
    printf("thread 1 exit code = %d\n", (int)ret);

    pthread_join(tid2, &ret);  // 等待线程2退出
    printf("thread 2 exit code = %d\n", (int)ret);

    return 0;
}

运行结果:

根据创建线程pthread_create函数的要求,新建线程函数原型必须返回一个void型指针。所以,以上例程的转换才看起来如此古怪,实际上是在用指针本身承载数据。在默认情况下,线程的终止状态会保存到对该线程调用pthread_join,所以即使两个子线程早早地退出,而主线程还没有走到pthread_join函数,这也是可以的。

下面介绍第三种退出方式:

int pthread_cancel(pthread_t tid);     // 请求取消同一进程中的指定线程

调用这个函数时,被取消线程如果下面的方式退出:

pthread_exit(PTHREAD_CANCELED);

注意,这个函数只是控制线程发出的一种请求,被取消线程不一定会被终止。我在被取消线程中加了一个死循环,于是它就无法响应这个退出请求,原因不清楚。

一个线程退出时,可以调用多个之前注册的线程清理处理程序。使用下面两个函数:

void pthread_cleanup_push(void (*rtn)(void *), void *arg);     // 注册清理函数
void pthread_cleanup_pop(int execute);     // 根据参数决定是否调用清理函数

注册的清理函数的调用顺序和栈一样,是后进先出类型的,就如同他们的名字一样。清理函数在下列情况下会被调用:

  • 线程调用pthread_exit时。
  • 响应其它线程发来的pthread_cancel取消请求时。
  • pthread_cleanup_pop的参数不为0时。

这里有一点需要注意,push和pop两个函数以宏的形式实现的,所以必须成对出现。下面是一个测试例程:

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

// 线程清理处理程序
void cleanup(void *arg)
{
    printf("cleanup : %s\n", (char *)arg);
}

void *thr_fn1(void *arg)
{
    pthread_cleanup_push(cleanup, "This is thread 1\n");
    return ((void *)1);       // 返回不会调用清理函数
    pthread_cleanup_pop(0); // 配对作用
}

void *thr_fn2(void *arg)
{
    pthread_cleanup_push(cleanup, "This is thread 2\n");
    pthread_exit((void *)2);   // exit时会调用清理函数
    pthread_cleanup_pop(0);     // 配对作用
}

void *thr_fn3(void *arg)
{
    pthread_cleanup_push(cleanup, "This is thread 3\n");
    sleep(3);               // 等待控制线程发出取消请求,然后调用清理函数
    pthread_cleanup_pop(0); // 配对作用
}

void *thr_fn4(void *arg)
{
    pthread_cleanup_push(cleanup, "This is thread 4\n");
    pthread_cleanup_pop(1); // 参数为0,则清理函数不被调用
}

int main(void)
{
    pthread_t tid1, tid2, tid3, tid4;

    pthread_create(&tid1, NULL, thr_fn1, NULL);
    pthread_create(&tid2, NULL, thr_fn2, NULL);
    pthread_create(&tid3, NULL, thr_fn3, NULL);
    pthread_create(&tid4, NULL, thr_fn4, NULL);

    pthread_cancel(tid3);

    sleep(3);

    return 0;
}

运行结果:

可以看出,线程2、3、4分别对应上述三种情况,而线程1由于是返回,所以不会调用注册的清理函数。

参考:

《unix环境高级编程》 P287-P297.

Linux线程终止

时间: 2024-10-12 16:52:22

Linux线程终止的相关文章

Linux 线程与进程,以及通信

http://blog.chinaunix.net/uid-25324849-id-3110075.html 部分转自:http://blog.chinaunix.net/uid-20620288-id-3025213.html 1.首先要明确进程和线程的含义: 进程(Process)是具有一定独立功能的程序关于某个数据集合上的一次运行活动,是系统进行资源分配和调度的一个独立单位.与程序相比,程序只是一组指令的有序集合,它本身没有任何运行的含义,只是一个静态实体.进程是程序在某个数据集上的执行,

Linux 线程模型的比较:LinuxThreads 与 NPTL

Linux 线程模型的比较:LinuxThreads 与 NPTL 本文参照来源:IBM开发者论坛 前奏:关于POSIX 可移植操作系统接口(英语:Portable Operating System Interface,缩写为POSIX),是IEEE为要在各种UNIX操作系统上运行的软件,而定义API的一系列互相关联的标准的总称,其正式称呼为IEEE Std 1003,而国际标准名称为ISO/IEC 9945.此标准源于一个大约开始于1985年的项目.POSIX这个名称是由理查德·斯托曼应IEE

linux线程资源回收

from:http://blog.csdn.net/skyflying2012/article/details/24655751及相关论坛 http://blog.chinaunix.net/uid-29783732-id-4485673.html 在写网络服务器程序时可能需要实现多线程接收多个客户端的数据,我实现方式比较傻,死循环等待client的connect,connect之后创建thread,这样其实有一个问题,服务器程序需要长期运行,长时间线程的创建,线程资源的回收就是一个问题. Li

Linux线程编程之信号处理

前言 Linux多线程环境中的信号处理不同于进程的信号处理.一方面线程间信号处理函数的共享性使得信号处理更为复杂,另一方面普通异步信号又可转换为同步方式来简化处理. 本文首先介绍信号处理在进程中和线程间的不同,然后描述相应的线程库函数,在此基础上给出一组示例代码,以讨论线程编程中信号处理的细节和注意事项.文中涉及的代码运行环境如下: 本文通过sigwait()调用来“等待”信号,而通过signal()/sigaction()注册的信号处理函数来“捕获”信号,以体现其同步和异步的区别. 一  概念

linux 线程详解

线程 是计算机中独立运行的最小单位,运行时占用很少的系统资源.可以把线程看成是操作系统分配CPU时间的基本单元.一个进程可以拥有一个至多个线程.它线程在进程内部共享地址空间.打开的文件描述符等资源.同时线程也有其私有的数据信息,包括:线程号.寄存器(程序计数器和堆栈指针).堆栈.信号掩码.优先级.线程私有存储空间. 为什么有了进程的概念后,还要再引入线程呢?使用多线程到底有哪些好处?什么的系统应该选用多线程?我们首先必须回答这些问题. 使用多线程的理由之一是和进程相比,它是一种非常"节俭&quo

Linux 线程浅析

进程和线程的区别与联系 在许多经典的操作系统教科书中,总是把进程定义为程序的执行实例,它并不执行什么, 只是维护应用程序所需的各种资源,而线程则是真正的执行实体. 为了让进程完成一定的工作,进程必须至少包含一个线程. 进程,直观点说,保存在硬盘上的程序运行以后,会在内存空间里形成一个独立的内存体,这个内存体有自己的地址空间,有自己的堆,上级挂靠单位是操作系统.操作系统会以进程为单位,分配系统资源,所以我们也说,进程是资源分配的最小单位. 线程存在与进程当中,是操作系统调度执行的最小单位.说通俗点

linux 线程函数大全

Technorati 标签: Linux thread 索引: 1.创建线程pthread_create 2.等待线程结束pthread_join 3.分离线程pthread_detach 4.创建线程键pthread_key_create 5.删除线程键pthread_key_delete 6.设置线程数据pthread_setspecific 7.获取线程数据pthread_getspecific 8.获取线程标示符pthread_self 9.比较线程pthread_equal 10.一次

Linux线程学习(二)

一.Linux进程与线程概述 进程与线程 为什么对于大多数合作性任务,多线程比多个独立的进程更优越呢?这是因为,线程共享相同的内存空间.不同的线程可以存取内存中的同一个变量.所以,程序中的所有线程都可以读或写声明过的全局变量.如果曾用fork() 编写过重要代码,就会认识到这个工具的重要性.为什么呢?虽然fork() 允许创建多个进程,但它还会带来以下通信问题:如何让多个进程相互通信,这里每个进程都有各自独立的内存空间.对这个问题没有一个简单的答案.虽然有许多不同种类的本地IPC (进程间通信)

Linux线程学习

线程基础 进程 系统中程序执行和资源分配的基本单位 每个进程有自己的数据段.代码段和堆栈段 在进行切换时需要有比较复杂的上下文切换 线程 减少处理机的空转时间,支持多处理器以及减少上下文切换开销, 比创建进程小很多 进程内独立的一条运行路线 处理器调度的最小单元,也称为轻量级进程 可以对进程的内存空间和资源进行访问,并与同一进程中的其他线程共享 线程相关的执行状态和存储变量放在线程控制表内 一个进程可以有多个线程,有多个线程控制表及堆栈寄存器,共享一个用户地址空间 多线程同步问题 线程共享进程的