线程问题的核心: 怎么退出线程才是合适的----小话多线程(2)
作者:陈曦
日期:2012-8-5 16:13:36
环境:[Mac 10.7.1 Lion Intel i3 支持64位指令 gcc4.2.1 xcode4.2 苹果开源代码Libc-763.11]
转载请注明出处
每日总结:优秀的架构都是类似的,垃圾的架构一般都是一个原因:代码内部原理掌握得不够
Q1: main函数中最后用return 0; 和使用 exit(0); 退出进程到底有什么不同?
A: 一种很简单的区别方式就是return 0是返回给调用函数者,而exit(0)是直接返回给系统。但是,前者返回给什么函数?写如下代码:
首先要确定,程序的入口点默认是_start. 同时可以看到,main中最后只是简单的返回给调用者;但是start中首先调用了main,然后调用了exit,这说明了虽然main函数最后没做什么退出进程的事情,返回到start后依然会退出进程。
再看第二个:
可以看到,main最后调用了exit函数,start最后依然也调用了exit,但是start最后调用的exit已经无法运行到,因为main调用后进程就结束了。
由上面两种情况可以看出,main函数最后调用return 0; 或者 exit(0); 可以说是基本一样,除了程序流程有点变化,没有什么大的区别。
Q2: 主线程最后调用pthread_exit来退出可行吗?
A: 如果仅仅从退出主线程的角度来考虑,这是可行的; 但是,一般来说,进程应该总是主线程最后退出,这样比较符合编程的基本原则;如果这样的话,主线程使用pthread_exit退出就可能出问题: 因为,它虽然会释放已经注册的清理函数以及线程特有的数据,但是它并不一定会释放进程相关的资源(包括内存、信号量、互斥体等)或者执行进程注册的退出函数(如atexit注册的退出函数),这样就很有可能导致内存泄露。当然,上面说并不一定,是因为,如果主线程是进程中最后退出的线程,那么进程相关的资源和进程注册的退出函数才会被执行。为了明白pthread_exit内部调用关系,首先,我们下载苹果开源代码Libc-763.11,这是对应mac系统10.7.1的开源libc代码,如果是其它系统,请下载对应版本的代码。苹果开源代码网站: http://opensource.apple.com/
首先找到pthread_exit的实现代码:
typedef struct _pthread{long sig; /* Unique signature for this structure */struct __darwin_pthread_handler_rec *__cleanup_stack;pthread_lock_t lock; /* Used for internal mutex on structure */uint32_tdetached:8,inherit:8,policy:8,freeStackOnExit:1,newstyle:1,kernalloc:1,schedset:1,wqthread:1,wqkillset:1,pad:2;size_t guardsize;/* size in bytes to guard stack overflow */#if !defined(__LP64__)int pad0;/* for backwards compatibility */#endifstruct sched_param param;uint32_tcancel_error;#if defined(__LP64__)uint32_tcancel_pad;/* pad value for alignment */#endifstruct _pthread *joiner;#if !defined(__LP64__)intpad1;/* for backwards compatibility */#endifvoid *exit_value;semaphore_t death;/* pthread_join() uses this to wait for death's call */mach_port_t kernel_thread; /* kernel thread this thread is bound to */void *(*fun)(void*);/* Thread start routine */ void *arg; /* Argment for thread start routine */int cancel_state; /* Whether thread can be cancelled */int err_no;/* thread-local errno */void *tsd[_EXTERNAL_POSIX_THREAD_KEYS_MAX + _INTERNAL_POSIX_THREAD_KEYS_MAX]; /* Thread specific data */ void *stackaddr; /* Base of the stack (is aligned on vm_page_size boundary */ size_t stacksize; /* Size of the stack (is a multiple of vm_page_size and >= PTHREAD_STACK_MIN) */mach_port_t reply_port; /* Cached MiG reply port */#if defined(__LP64__) intpad2;/* for natural alignment */#endifvoid *cthread_self; /* cthread_self() if somebody calls cthread_set_self() *//* protected by list lock */uint32_t childrun:1,parentcheck:1,childexit:1,pad3:29;#if defined(__LP64__)intpad4;/* for natural alignment */#endifTAILQ_ENTRY(_pthread) plist;void *freeaddr;size_tfreesize;mach_port_tjoiner_notify;charpthread_name[MAXTHREADNAMESIZE];/* including nulll the name */ intmax_tsd_key;void *cur_workq;void * cur_workitem;uint64_t thread_id;} *pthread_t;
总之,线程退出不是什么多么可怕的东西,操作系统大量用线程技术,上层的软件也不应该对此如此惧怕。
pthread_exit和pthread_cancel都是不错的选择; 不过,需要注意清理函数、资源释放的正确,以减少死锁问题的产生,减少线程意外崩溃问题的产生。
作者:陈曦
日期:2012-8-5 16:13:36
环境:[Mac 10.7.1 Lion Intel i3 支持64位指令 gcc4.2.1 xcode4.2 苹果开源代码Libc-763.11]
转载请注明出处
每日总结: 优秀的架构都是类似的,垃圾的架构一般都是一个原因:代码内部原理掌握得不够