UNIX环境高级编程(十一章)线程

本文详细探讨了线程与进程的概念,重点介绍了线程标识、创建、终止及同步机制。深入分析了线程ID、创建过程、线程退出方式与线程清理处理程序,以及如何通过pthread_create和pthread_join函数实现线程间同步。通过对比线程与进程,阐述了它们在共享资源、独立性和执行环境方面的差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

11.2线程概念

线程包含了表示进程内执行环境的必须信息,其中包含进程中表示线程的线程ID,一组寄存器值,栈,调度优先级和策略。信号屏蔽字,errno值以及线程私有数据

进程的所有信息对该进程的所有线程都是共享的,包括可执行的程序文本,程序的全局内存和堆内存,栈以及文件描述符。

11.3线程标识

就像每一个进程都有一个进程ID一样,每一个线程也有一个线程ID,进程ID在整个系统中是唯一的,但线程ID不同,线程ID只在它所属的进程环境中有效。线程ID用pthread_t数据类型来表示,(Linux使用无符号长整数表示pthread_t结构)。实现的时候可以用一个结构来代表pthread_t数据类型,所以可移植的系统不能把它当做整数来处理,因此必须使用函数来对两个线程ID进行比较

#include<pthread.h>
int pthread_equal(pthread_t tid1,pthread_t tid2);//返回0表示相等


线程可以通过pthread_self函数获取自身的线程ID

#include<pthread.h>
pthread_t pthread_self(void)
//返回线程的线程ID


11.4线程创建

在传统unix模型中,每个进程只有一个控制线程,它也是以单个控制线程启动的。新增的线程可以通过pthread_create函数创建

#include<pthread.h>
pthread_t pthread_create(pthread_t  *tidp,const pthread_attr_t *attr,void *(*start_rtn)(void),void * arg)//若成功返回0,否则返回错误编号


当pthread_create成功返回时,由tidp指向的内存单元被设置为新创建线程的线程ID,attr参数用于定制不同的线程属性。

新创建的线程将从start_rtn函数的地址开始运行,该函数只有一个无类型的参数arg,如果要向start_rtn函数传递的参数不止一个,那么需要把参数房贷一个结构中,然后把这个结构的地址当做arg参数传入。

线程创建时不能保证哪一个线程先运行,可以是新线程也可以是调用线程,新创建的线程可以访问进程的地址空间,并且继承调用线程的浮点环境和信号屏蔽字,但是该线程的未决信号集被清除。

注意pthread_create函数在调用失败是通常会返回错误码,他们并不像其他函数一样设置errno。每个线程提供一个errno副本,只是为了与使用errno的现有函数兼容。

11.5线程终止

如果进程中某一个线程调用了exit,_exit或者_Exit,那么整个进程就会终止。类似的,如果信号的默认动作是终止进程,那么把该信号发送到某个线程,整个进程都会终止。

单个线程可以有三种方式退出:
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)
//成功返回0,否则返回错误码

调用线程一直阻塞,直到等待线程调用pthread_exit,从启动例程中返回或被取消。

如果只是从他的启动例程中返回,那么rval_ptr将包含返回码,如果线程被取消,由rval_ptr指向的内存单元就置为PTHREAD_CANCLE。

如果线程已经处于分离状态,那么,pthread_join调用就会失败。

pthread_create和pthread_exit函数的无类型指针参数能传递的数值不止一个,该指针可以传递更复杂信息的结构地址,但是注意这个结构所使用的内存,在调用者完成调用以后必须仍然是有效的,否则就会出现无效或者非法内存访问。例如在调用线程的栈上分配了该结构,那么其他线程在使用这个结构时内存可能就已经改变了。(可以使用全局栈结构malloc调用分配结构)。

线程可以调用pthread_cancle函数来请求取消统一进程中的其他线程。

#inlcude<pthread.h>
int pthread_cancle(pthread_t tid);
//返回值为0成功,否则返回错误编号


在默认情况下,pthread_cancle函数会使由tid标识的线程行为如同调用了参数为PTHREAD_CANCLE的pthread_exit函数,注意pthread_cancle并等待线程终止,它仅仅提出请求。

线程可以安排退出时它调用的函数,这样的函数成为线程清理处理程序。处理程序记录在栈中,也会就是说他们的执行顺序与注册时相反。

#inlcude<pthread.h>
void pthread_cleanup_push(void* (*rtn)(void*),void *arg);
void pthread_cleanup_pop(int excute)

线程清理函数会被调用时的情况:
调用pthread_exit时

响应取消请求时

用非0excute参数调用pthread_cleanup_pop函数时

如果excute参数为0时,清理函数将不会调用(如果相处通过它的启动例程返回的话那么就不会调用清理函数)

 

在默认情况下,线程的终止状态会保存到对该线程调用pthread_exit,如果线程已经处于分离状态,线程的底层资源可以在线程终止时立即收回。phtread_detach函数用于使线程进入分离状态

#inlcude<pthread.h>
int pthread_detach(pthread_t tid);
//若成功返回0,否则返回错误代码


11.6线程同步

会在UNIX网络编程中介绍线程的同步

 
 
现在可以看出,线程和进程函数有很多相似之处。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值