线程

线程概念

在⼀个程序⾥的⼀个执⾏路线就叫做线程( thread)。更准确的定义是:线程是⼀个进程内部的控制序列。
⼀切进程⾄少都有⼀个执⾏线程。
在Linux中,目前的线程实现是 Native POSIX Thread Libaray,简称NPTL。在这种实现下,线程⼜被称为轻量级进程(Light Weighted Process),每⼀个⽤户态的线程,在内核中都对应⼀个调度实体,也拥有⾃⼰的进程描述符 (task_struct结构体)。
进程和线程
进程是承担分配系统资源的一个基本实体;
线程是CPU调度的进本单位;
线程共享进程数据,但也用友自己的一部分数据:线程ID、一组寄存器、栈、errno、信号屏蔽字、调度优先级;
线程是在进程的地址空间内运行;
线程的执行力度比进程更细;
一个进程的多个资源共享
同⼀地址空间,因此Text Segment、Data Segment都是共享的,如果定义⼀个函数,在各线程中都可以调⽤,如果定义⼀个全局变量 ,在各线程中都可以访问到 ,除此之外,各线程还共享以下进程资源和环境:
⽂件描述符表;
每种信号的处理⽅式 (SIG_ IGN、SIG_ DFL或者⾃定义的信号处理函数 );
当前⼯作目录;
⽤户id和组id。
线程的优点
创建⼀个新线程的代价要⽐创建⼀个新进程⼩得多;
与进程之间的切换相⽐,线程之间的切换需要操作系统做的⼯作要少很多;
线程占⽤的资源要⽐进程少很多;
能充分利⽤多处理器的可并⾏数量;
在等待慢速I/O操作结束的同时,程序可执⾏其他的计算任务;
计算密集型应⽤,为了能在多处理器系统上运⾏,将计算分解到多个线程中实现;
I/O密集型应⽤,为了提⾼性能,将 I/O操作重叠。线程可以同时等待不同的 I/O操作。
线程的缺点
性能损失:⼀个很少被外部事件阻塞的计算密集型线程往往⽆法与共它线程共享同⼀个处理器。如果计算密集型线程的数量⽐可⽤的处理器多,那么可能会有较⼤的性能损失,这⾥的性能损失指的是增加了额外的同步和调度开销,⽽可⽤的资源不变。
健壮性降低:编写多线程需要更全⾯更深⼊的考虑,在⼀个多线程程序⾥,因时间分配上的细微偏差
或者因共享了不该共享的变量⽽造成不良影响的可能性是很⼤的,换句话说线程之间是缺乏保护的。
缺乏访问控制:进程是访问控制的基本粒度,在⼀个线程中调⽤某些 OS函数会对整个进程造成影响。
编程难度提高:编写与调试⼀个多线程程序⽐单线程程序困难得多。

线程控制

POSIX线程库
与线程有关的函数构成了⼀个完整的系列,绝⼤多数函数的名字都是以 “pthread_”打头的;
要使⽤这些函数库,要通过引⼊头⽂;
链接这些线程函数库时要使⽤编译器命令的 “-lpthread”选项。
创建线程
功能:创建⼀个新的线程。
原型:

    int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg);
参数:
    thread:返回线程ID
    attr:设置线程的属性,attr为NULL表⽰使⽤默认属性
    start_routine:是个函数地址,线程启动后要执⾏的函数
    arg:传给线程启动函数的参数
返回值:成功返回0;失败返回错误码。

错误检查:
传统的⼀些函数是,成功返回 0,失败返回-1,并且对全局变量errno赋值以指⽰错误。
pthreads函数出错时不会设置全局变量 errno(⽽⼤部分其他POSIX函数会这样做)。⽽是将错误代码通过返回值返回。
pthreads同样也提供了线程内的 errno变量,以⽀持其它使⽤ errno的代码。对于pthreads函数的错误,建议通过返回值业判定,因为读取返回值要⽐读取线程内的 errno变量的开销更⼩。
线程终止
如果需要只终⽌某个线程⽽不终⽌整个进程 ,可以有三种⽅法:
1. 从线程函数return。这种⽅法对主线程不适⽤ ,从main函数return相当于调⽤exit。
2. 线程可以调⽤pthread_ exit终⽌⾃⼰。
3. ⼀个线程可以调⽤pthread_ cancel终⽌同⼀进程中的另⼀个线程。
pthread_exit函数:

功能:线程终止
原型:
    void pthread_exit(void *value_ptr);
参数:
    value_ptr:value_ptr不要指向某个局部变量。
返回值:无返回值,跟进程一样,线程结束的时候无法返回到它的调用者(自身)。

注意:pthread_exit或者return返回的指针所指向的内存单元必须是全局的或者是⽤ malloc分配的,不能在线程函数的栈上分配,因为当其它线程得到这个返回指针时线程函数已经退出了。
pthread_cancel函数:

功能:取消一个执行中的线程。
原型:
    int pthread_cancel(pthread_t thread);
参数:
    thread:线程ID
返回值:成功返回0;失败返回错误码。

线程等待与分离
线程等待
为什么需要线程等待?
已经退出的线程,其空间没有被释放,仍然在进程的地址空间内。
创建新的线程不会复⽤刚才退出线程的地址空间。

功能:等待线程结束。
原型:
    int pthread_join(pthread_t thread, void **value_ptr);
参数:
    thread:线程ID
    value_ptr:它指向一个指针,后者指向线程的返回值。
返回值:成功返回0;失败返回错误码。

调用该函数的线程将挂起等待 ,直到id为thread的线程终⽌。thread线程以不同的⽅法终⽌ ,通过pthread_join得到的终⽌状态是不同的,总结如下 :
1. 如果thread线程通过return返回,value_ ptr所指向的单元⾥存放的是 thread线程函数的返回值。
2. 如果thread线程被别的线程调⽤ pthread_ cancel异常终掉,value_ ptr所指向的单元⾥存放的是常数PTHREAD_ CANCELED。
3. 如果thread线程是⾃⼰调⽤pthreadexit终⽌的,valueptr所指向的单元存放的是传给 pthread_exit的参数。
4. 如果对thread线程的终⽌状态不感兴趣 ,可以传NULL给value_ ptr参数。
分离线程
默认情况下,新创建的线程是 joinable的,线程退出后,需要对其进⾏ pthread_join操作,否则⽆法释放资源,从⽽造成系统泄漏。
如果不关⼼线程的返回值, join是⼀种负担,这个时候,我们可以告诉系统,当线程退出时,⾃动释放线程资源。

int pthread_detach(pthread_t thread);

可以是线程组内其他线程对⺫标线程进⾏分离,也可以是线程⾃⼰分离.

pthread_detach(pthread_self());

joinable和分离是冲突的,⼀个 线程不能既是joinable⼜是分离的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值