一般情况下,线程终止后,其终止状态一直保留到其它线程调用pthread_join获取它的状态为止。但是线程也可以被置为detach状态,这样的线程一旦终止就立刻回收它占用的所有资源,而不保留终止状态。不能对一个已经处于detach状态的线程调用pthread_join,这样的调用将返回EINVAL错误。也就是说,如果已经对一个线程调用了pthread_detach就不能再调用pthread_join了。

pthread_cancel函数

杀死(取消)线程            其作用,对应进程中 kill() 函数。

    int pthread_cancel(pthread_t thread);    成功:0;失败:错误号

    【注意】:线程的取消并不是实时的,而有一定的延时。需要等待线程到达某个取消点(检查点)。

    类似于玩游戏存档,必须到达指定的场所(存档点,如:客栈、仓库、城里等)才能存储进度。杀死线程也不是立刻就能完成,必须要到达取消点。

    取消点:是线程检查是否被取消,并按请求进行动作的一个位置。通常是一些系统调用creat,open,pause,close,read,write..... 执行命令man 7 pthreads可以查看具备这些取消点的系统调用列表。也可参阅 APUE.12.7 取消选项小节。

可粗略认为一个系统调用(进入内核)即为一个取消点。如线程中没有取消点,可以通过调用pthread_testcancel()函数自行设置一个取消点。

被取消的线程,    退出值定义在Linux的pthread库中。常数PTHREAD_CANCELED的值是-1。可在头文件pthread.h中找到它的定义:#define PTHREAD_CANCELED ((void *) -1)。因此当我们对一个已经被取消的线程使用pthread_join回收时,得到的返回值为-1。

【练习】:终止线程的三种方法。注意"取消点"的概念。                                    【pthrd_endof3.c】

终止线程方式

总结:终止某个线程而不终止整个进程,有三种方法:

  1. 从线程主函数return。这种方法对主控线程不适用,从main函数return相当于调用exit。
  2. 一个线程可以调用pthread_cancel终止同一进程中的另一个线程。
  3. 线程可以调用pthread_exit终止自己。

pthread_equal函数

比较两个线程ID是否相等。

    int pthread_equal(pthread_t t1, pthread_t t2);

    有可能Linux在未来线程ID pthread_t 类型被修改为结构体实现。

控制原语对比

    进程            线程

    fork            pthread_create

    exit            pthread_exit

    wait            pthread_join

    kill            pthread_cancel

    getpid        pthread_self        命名空间

接下来看代码:

#include
<pthread.h>

#include
<stdio.h>

#include
<stdlib.h>

void *func1(void * f1)

{

    puts("我是第一个线程!我采用return的方式结束自己。");

    return (void*)770880;

}

void *func2(void * f2)

{

    puts("我是第二个线程!我采用pthread_exit的方式结束自己。");

    pthread_exit((void*)1314);

}

void *func3(void * f3)

{

    puts("我是第三个线程!我采用pthread_cancel的方式结束自己。");

    while (1)//可能会发生线程执行完但是主线程还没有开始调用pthread_cancel函数。

        pthread_testcancel();//主动设置取消点

    return (void*)520;

}

int main(void)

{

    pthread_t pth[3];

    void *i;

    pthread_create((pth + 0), NULL, func1, NULL);

    pthread_join(pth[0], (void**)&i);

    printf("线程一的退出状态:i = %d.\n", (int)i);

    pthread_create((pth + 1), NULL, func2, NULL);

    pthread_join(pth[1], (void**)&i);

    printf("线程二的退出状态:i = %d.\n", (int)i);

    pthread_create((pth + 2), NULL, func3, NULL);

    pthread_cancel(pth[2]);//杀死

    pthread_join(pth[2], (void**)&i);

    printf("线程三的退出状态:i = %d.\n", (int)i);

    return 0;

}

结果:

很简单,就这样吧。

Linux:结束线程的三种方式的更多相关文章

  1. 0036 Java学习笔记-多线程-创建线程的三种方式

    创建线程 创建线程的三种方式: 继承java.lang.Thread 实现java.lang.Runnable接口 实现java.util.concurrent.Callable接口 所有的线程对象都 ...

  2. (转)Java结束线程的三种方法

    背景:面试过程中问到结束线程的方法和线程池shutdown shutdownnow区别以及底层的实现,当时答的并不好. Java结束线程的三种方法 线程属于一次性消耗品,在执行完run()方法之后线程 ...

  3. Java结束线程的三种方法(爱奇艺面试)

    线程属于一次性消耗品,在执行完run()方法之后线程便会正常结束了,线程结束后便会销毁,不能再次start,只能重新建立新的线程对象,但有时run()方法是永远不会结束的.例如在程序中使用线程进行So ...

  4. java创建线程的三种方式及其对比

    第一种方法:继承Thread类,重写run()方法,run()方法代表线程要执行的任务.第二种方法:实现Runnable接口,重写run()方法,run()方法代表线程要执行的任务.第三种方法:实现c ...

  5. AJPFX总结java创建线程的三种方式及其对比

    Java中创建线程主要有三种方式: 一.继承Thread类创建线程类 (1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务.因此把run()方法称为执行 ...

  6. java创建线程的三种方式及其对照

    Java中创建线程主要有三种方式: 一.继承Thread类创建线程类 (1)定义Thread类的子类.并重写该类的run方法,该run方法的方法体就代表了线程要完毕的任务.因此把run()方法称为运行 ...

  7. Java并发编程:Java创建线程的三种方式

    目录 引言 创建线程的三种方式 一.继承Thread类 二.实现Runnable接口 三.使用Callable和Future创建线程 三种方式的对比 引言 在日常开发工作中,多线程开发可以说是必备技能 ...

  8. Java实现线程的三种方式和区别

    Java实现线程的三种方式和区别 Java实现线程的三种方式: 继承Thread 实现Runnable接口 实现Callable接口 区别: 第一种方式继承Thread就不能继承其他类了,后面两种可以 ...

  9. Linux 软件安装的三种方式

    Linux 软件安装的三种方式 1.yum ​ 语法格式: ​ yum -y install package.name ​ -y yes # 遇到提示自动输入yes ​ 案例: 安装ifconfig命 ...

随机推荐

  1. [UE4]圆形小地图

    一.创建一个名为M_RoundRetainer的材质 二.创建一个名为RoundMiniMap的UserWidget 三.TestMiniMap中将添加进来 四.运行游戏

  2. [UE4]蓝图使用GameMode重构

    GameMode的生命周期贯穿整个游戏,当然也包括各个关卡.因此可以把各个关卡都需要的功能放置在GameMode,以达到功能共享.重复利用的目的!

  3. mysql为什么要分库分表?

    1 基本思想之什么是分库分表?从字面上简单理解,就是把原本存储于一个库的数据分块存储到多个库上,把原本存储于一个表的数据分块存储到多个表上. 2 基本思想之为什么要分库分表? 单表操作数据量有最优值, ...

  4. 一行代码避免OkHttp的网络库应用被抓包

    在建立socket连接之前,OkHttp会获取系统的代理信息,如果设置代理,那么通过DNS解析其IP然后使用代理IP来建立socket连接.如果没有设置代理,那么会使用请求中的url的IP地址,来建立 ...

  5. switch case 变量初始化问题

    今天再写alsa的时候遇到一个稀奇古怪的问题,网上看了下资料,摘出来入下 代码: int main() { ; switch(a) { : ; break; : break; default: bre ...

  6. ext.net tooltip

    业务场景:需要对grid表格中指定列显示tooltip. html: <form id="form1" runat="server"> <To ...

  7. Can't create handler inside thread that has not called Looper.prepare()

    Looper.prepare(); // Can't create handler inside thread that has not called Looper.prepare(). Toast. ...

  8. sqlserver默认的内存策略

    sqlserver默认的内存策略,如果内存足够大,没有限制的话,会把一次搜索结果都放在内存中,下次搜索如果数据没发生变化(数据库缓存依赖策略),那么直接在内存数据中搜索,而不重新加载数据.可以通过每次 ...

  9. 添加删除mysql用户

    create user 'hive_user'@'%' identified by '密码'; grant all privileges on hive.* to hive_user@'%'; cre ...

  10. 自媒体运营排版利器----Markdown here

    Markdown Here ​ 下载chrome插件直接下载 使用:打开网页文章编辑器,比如cnblog 用markdown语法写文章,之后点击编译 可以设置好css语法,以后每次可以套用同样的模板 ...