Linux线程的生命周期

《Unix环境高级编程》、《Posix多线程程序设计》学习笔记和重点摘要。

一、线程的4种状态

状态
含义
就绪(Ready)
线程能够运行,但在等待可用的处理器。可能刚刚创建启动,或刚刚从阻塞中恢复,或者被其他线程抢占
运行(Running)
线程正在运行。在多处理器系统中,可能有多个线程处于运行态
阻塞(Blocked)
线程由于等待处理器外的其他条件无法运行,如条件变量的改变、加锁互斥量或I/O操作结束
终止(Terminated)
线程从起始函数中返回,或者调用pthread_exit,或者被取消,终止自己并完成所有资源清理工作。不是被分离,也不是被连接
        每个状态可能会细分成几个“子状态”。

二、线程的创建
        需要创建线程的方式有:    1、调用pthread_create
                                                   2、进程的信号通知机制设为SIGEV_THREAD
        注意:新线程可能在当前线程从phtread_create返回之前就运行了。甚至在pthread_create还没返回,新线程就已经执行完了。

        线程和初始进程的一些区别:
        1,参数不同
        2,函数返回结果不同:初始进程从main函数返回后,进程和进程内的所有线程都将终止;普通线程返回时,不影响进程内的其他线程。
             如果你希望在初始进程终止时,进程中的其他线程继续执行,则需要在初始进程中调用pthread_exit,而不是从main函数中返回。
        3,大多数系统中,初始线程运行在默认进程堆栈上,该堆栈可以增长到足够的尺寸;而在某些实现中,普通线程的堆栈空间是受限的,如果
            线程堆栈溢出,则程序会因段错误或总线错误而失败。

三、运行和阻塞
        线程阻塞的原因可能是:    1,试图加锁一个已经被锁住的互斥量
                                                   2,等待某个条件变量
                                                  3,调用Singwait等待尚未发生的信号
                                                  4,执行无法立即完成的I/O操作
                                                  5,线程还会由于如内存页错误之类的系统操作而被阻塞



四、终止
        单个线程可以通过3种方式退出,在不终止整个进程的情况下停止它的控制流:
        1,线程只是从启动例程中返回,返回值是线程的退出码。
        2,线程可以被同一进程中的其他线程取消。
        3,线程调用pthread_exit

头文件
#include <pthread.h>
函  数
void pthread_exit (void *rval_ptr)
        rval_ptr是一个无类型指针,进程中的其他线程可以通过调用pthread_join函数返回到这个指针。

头文件
#include <pthread.h>
函  数
int pthread_join (pthread_t thread, void **rval_ptr)
        线程将一直被阻塞,直到上面三种方法终止线程。 pthread_join 自动把连接的线程置于分离状态,这样资源
就可以恢复。如果线程已经处于分离状态,pthread_join 就会调用失败,返回EINVAL。

头文件
#include <pthread.h>
函  数
int pthread_detach( pthread_t  tid)
        使线程进入分离状态。线程在处于分离状态时,线程的底层存储资源可以在线程终止时立即被回收。在分离
状态下不能使用pthread_join等待线程的终止状态。

头文件
#include <pthread.h>
函  数
int pthread_cancel (pthread_t thread)
调用此函数来请求取消同一进程中的其他线程。线程可以选择忽略。

注意:如果线程只是从当前线程返回或者调用pthread_exit正常终止,rval_ptr将包含返回码。但是
如果线程被取消,由rval_ptr指定的内存单元就置为PTHREAD_CANCELED.

注意:pthread_create和pthread_exit函数的无类型指针参数能传递的数值可以不止一个,该指针可以传递包含更复杂信息
的结构的地址,但是注意这个结构所使用的内存在调用者完成 调用以后必须保证仍是有效的,否则就会出现非法内存访问。
例如,在调用线程(如main函数)的栈上分配了一个结构体,那么其他的线程在使用这个结构体时,结构体中的内容可能已经
改变了。
        又如,线程在自己的栈上分配了一个结构体,然后把它的指针传递给pthread_exit,那么当调用pthread_join的线程试图
再次使用该结构时,这个栈可能已经撤销,这块内存可能另作他用。
        解决的办法:可以使用全局结构体,不要放在main中。或者使用malloc函数分配结构体内存。

头文件
#include <pthread.h>
函  数
void pthread_cleanup_push (void (*rtn) (void *), void *arg)
函  数
void pthread_cleanup_pop (int execute)
        进程可以通过atexit函数安排进程退出时需要调用的函数,线程同样可以。这样的函数被称为“线程清理处理程序”。线程
可以建立多个清理处理程序。处理程序记录在栈中,这也意味着它们的执行顺序和它们的注册顺序是相反的。
        当线程执行以下动作时调用清理函数,调用参数为arg,清理函数rtn的调用顺序是pthread_cleanup_push函数来安排的。
        1,调用pthread_exit时
        2,响应取消请求时
        3,用非0 execute参数调用pthread_cleanup_pop时(如果execute参数设置为0时,清理函数将不被调用。但无论哪种情况,pthread_cleanup_pop都将删除上次pthread_cleanup_push调用建立的清理处理函数)

注意:从线程自然的返回(如return)而终止线程的将不会调用线程清理函数。

进程原语和线程原语的比较
进程原语
线程原语
描述
fork
pthread_create
创建新的控制流
exit
pthread_exit
从现有的控制流中退出
waitpid
pthread_join
从控制流中得到退出状态
atexit
pthread_cleanup_push 
注册在退出控制流时要调用的函数
getpid
pthread_self
获取所在控制流的ID
abort
pthread_cancel
请求控制流的非正常退出
        
五、回收
        线程在终止后都要经过分离并且将资源回收。
        回收将释放所有在线程终止时未释放的系统和进程资源,包括保存线程返回值的内存空间、堆栈、保存
寄存器状态的内存空间等。在线程终止后上述资源就不该被访问了。
        终止线程将释放所有的系统资源,但你必须释放由该线程占有的程序资源。调用malloc或mmap分配的
内存可以在任何时候、由任何线程释放。互斥量、条件变量和信号灯可以由任何线程销毁,只要它们被解锁
并且没有线程等待。
        但是,只有互斥量的主人能够解锁它。如果线程终止时还有加锁的互斥量,则该互斥量就不能被再次使
用,因为不会被解锁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值