线程终止方式

一般来说,Posix的线程终止有两种情况:正常终止和非正常终止。线程主动调用pthread_exit()或者从线程函数中return都将使线程正常退出,这是可预见的退出方式;非正常终止是线程在其他线程的干预下,或者由于自身运行出错(比如访问非法地址)而退出,这种退出方式是不可预见的。

线程终止的同步及其返回值

一般情况下,进程中各个线程的运行都是相互独立的,线程的终止并不会通知,也不会影响其他线程,终止的线程所占用的资源也并不会随着线程的终止而得到释放。正如进程之间可以用wait()系统调用来同步终止并释放资源一样,线程之间也有类似机制,那就是pthread_join()函数。

void pthread_exit(void *retval) int pthread_join(pthread_t th, void **thread_return) int pthread_detach(pthread_t th)

pthread_join()的调用者将挂起并等待th线程终止,retval是pthread_exit()调用者线程(线程ID为th)的返回值,如果thread_return不为NULL,则*thread_return=retval。需要注意的是一个线程仅允许唯一的一个线程使用pthread_join()等待它的终止,并且被等待的线程应该处于可join状态,即非DETACHED状态。

如果进程中的某个线程执行了pthread_detach(th),则th线程将处于DETACHED状态,这使得th线程在结束运行时自行释放所占用的内存资源,同时也无法由pthread_join()同步,pthread_detach()执行之后,对th请求pthread_join()将返回错误。

一个可join的线程所占用的内存仅当有线程对其执行了pthread_join()后才会释放,因此为了避免内存泄漏,所有线程的终止,要么已设为DETACHED,要么就需要使用pthread_join()来回收。

关于pthread_exit()和return

理论上说,pthread_exit()和线程宿体函数退出的功能是相同的,函数结束时会在内部自动调用pthread_exit()来清理线程相关的资源。但实际上二者由于编译器的处理有很大的不同。

在进程主函数(main())中调用pthread_exit(),只会使主函数所在的线程(可以说是进程的主线程)退出;而如果是return,编译器将使其调用进程退出的代码(如_exit()),从而导致进程及其所有线程结束运行。

其次,在线程宿主函数中主动调用return,如果return语句包含在pthread_cleanup_push()/pthread_cleanup_pop()对中,则不会引起清理函数的执行,反而会导致segment fault。

时间: 11-15

线程终止方式的相关文章

深入解析父子线程(父子线程相互独立,子线程使用自己的栈空间,进程要等到所有线程终止运行之后才终止运行)

说起多线程,我们可以说起一大堆和它相关的有趣话题来,比如什么子孙线程关系,父子线程关系,线程同步异步之类的研究话题来,而我今天所说的,是关于父子线程的一些有趣现象. 首先提出一个问题,“在多线程的应用程序中,当父线程结束之后,子线程会不会退出呢?”,本文将围绕这个问题,深入分析windows中父子线程的生命周期及他们之间的关系. 我们知道,不管你使用的是何种编程语言,但当我们在windows下编程,且使用了平台相关性的库的时候,不管我们使用什么函数来创建线程,最终的结果是,我们的代码中都会调用C

python基础-线程创建方式

python中提供了两种创建线程的方式 1.采用thread.start_new_thread(funciton,args..) 2.集成Thread类 第一种方式 import thread as t import time #Define a function for the thread def print_time(threadName,delay): count=0; while count<5: time.sleep(delay) count+=1 print "%s(%s):

cocos2dx2.0 与cocos2dx3.1 创建线程不同方式总结

虽然内容是抄过来的,但是经过了我的验证,而且放在一起就清楚很多了,cocos2dx版本经常变化很大,总会导致这样那样的问题. cocos2dx2.0 中 1. 头文件 #include <pthread.h> ... pthread_t serial_thread_id; // 起这个名字本打算用在socket上的 int serialThreadStart(void);// 启动线程的方法 static void* serialReceiverFun(void *arg);// 被启动的线程

MFC 线程创建方式

MFC 分UI线程和工作线程,一般现在的应用程序都是一个主UI线程和N个工作线程来完成工作.主UI线程获取到工作线程发送的信息来刷新界面. 不过因为工作需要,MFC有要维护的项目,因此就学习一下MFC创建UI线程,使用工作线程的方式. 1.UI线程,继承CWinThread类  1 class CAddDeviceApp : public CWinThread 2 { 3     DECLARE_DYNCREATE(CAddDeviceApp) 4 protected: 5     CAddDe

线程同步方式比较

用户模式下的方法有:原子操作(例如一个单一的全局变量),临界区. 内核模式下的方法有:事件,信号量,互斥量. 临界区 保证在某一时刻只有一个线程能访问数据的简便办法.在任意时刻只允许一个线程对共享资源进行访问.如果有多个线程试图同时访问临界区,那么 在有一个线程进入后其他所有试图访问此临界区的线程将被挂起,并一直持续到进入临界区的线程离开.临界区在被释放后,其他线程可以继续抢占,并以此达到用原子方式操 作共享资源的目的. 仅能在同一进程内使用 互斥量 Mutex 互斥量跟临界区很相似,只有拥有互

3种启动线程的方式

线程和进程的关系:  一个进程有N个线程 1.实现线程的三种方式: (1)继承thread 类 [1]创建一个继承thread类的类 package Thread01; public class MyThread extends Thread { private int i; @Override public void run() { for (; i < 10; i++) { System.out.println(getName()+"\t"+i); } } } [2]创建测试

序列化和反序列化及线程实现方式

一.序列化与反序列化       把对象转换为字节序列的过程称为对象的序列化. 把字节序列恢复为对象的过程称为对象的反序列化. 对象的序列化主要有两种用途: 1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中: 2) 在网络上传送对象的字节序列. 序列化关键代码如下: 定义Person类实现序列化.重写toString方法,定义无参以及带参构造 定义类 public class MySerialize { public static void main(String[] args)

多线程基础:两种常见的创建线程的方式

一 通过继承Thread 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package thread; public class ThreadDemo1 {     public static void main(String[] args) {         Demo1 demo1 = new Demo1("zifangsky");         Demo1 demo2 = new Demo1(

线程开启方式2—任务

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading; 6 using System.Threading.Tasks; 7 8 namespace 线程开启4_任务 9 { 10 class Program 11 { 12 13 private static void taskMethod() 14 { 15 Co

传统线程实现方式

1.new 一个Thread子类(这里是一个内部类)通常写法如SubThread Thread thread=new Thread(){ @Override public void run(){ while(true){ try { Thread.sleep(500); System.out.println("0:"+Thread.currentThread()); System.out.println("1:"+this.currentThread()); } c