线程创建与终止(Linux_C++)


线程的创建及终止

线程 ID

线程 ID 只在它所属的进程环境有效,并用 pthread_t 数据类型来表示,实现的时候可以用一个结构来代表 pthread_t 数据类型,所以在可移植的操作系统实现不能把它当做为整数来处理。因此必须使用函数(pthread_equal)来对两个线程 ID 进行比较。可以用 pthread_self 获取自身线程 ID 。  

线程的创建

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

errno

注意 pthread 函数在调用失败时通常会返回错误代码,它们并不像其他的 POSIX 函数一样设置 errno。每个线程都提供 errno 的副本,这只是为了与使用 errno 的现有函数兼容。在线程中,从函数中返回的错误码更为清晰整洁,不需要依赖那些随着函数执行不断变化的全局状态,因而可以把错误的范围限制在引起出错的函数中。

线程的终止

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

单个线程终止三种方式

    • 线程只是从启动例程中返回,返回值是线程的退出码。
    • 线程可以被同一进程的其他线程取消(线程可以通过 pthread_cancel 函数来请求取消同一进程中的其他线程,默认情况下,pthread_cancel 函数会使得指定的线程的行为表现为如同调用了参数为 PTHREAD_CANCELED 的 pthread_exit 函数。但是线程可以选择忽略取消方式或是控制取消方式,,pthread_cancel 并不等待线程终止,它仅仅提交请求)。
    • 线程调用 pthread_ext (在 pthread_exit 可以在退出的时候可以传递一些信息,那这些信息可以用 pthread_join 函数获得,那么调用 pthread_join 函数将会一直阻塞,直到指定的线程调用 pthread_exit)。

在默认情况下,线程的终止状态会保存到该线程调用 pthread_join,如果线程已经处于分离状态,线程的底层存储资源可以在线程终止时立即被回收。当线程被分离时,并不能用 pthread_join 函数等待它的终止状态。对分离状态的线程进行 pthread_join 的调用可以产生失败,返回 EINVAL。pthread_detach 调用可以用于使线程进入分离状态。

资料: 

线程清理处理程序

线程可以安排它退出时需要的函数,这与进程可以用 atexit 函数安排进程退出时需要调用的函数是类似的。这样的函数称为线程清理处理程序。线程可以建立多个清理处理程序,处理程序记录在栈中,也就是说它们的执行顺序与它们注册时的顺序相反

    • pthread_cleanup_push(..)  将线程清理处理程序压栈
    • pthread_cleanup_pop(..)    将线程清理处理程序出栈

 当线程执行以下动作时调用清理函数,调用参数 arg,清理函数 rtn 的调用顺序是由 pthread_cleanup_push 函数来安排的。

    • 调用 pthread_exit 时
    • 响应取消请求时
    • 用非零 execute 参数调用 pthread_cleanup_pop 时

如果 execute 参数设置为 0,清理函数将不会被调用。无论哪种情况,pthread_cleanup_pop 都将删除上次 pthread_clean_push 调用建立的清理处理程序

线程睡眠、阻塞、挂起的区别与解释

首先这些术语都是对于线程来说的。对线程的控制就好比你控制了一个雇工为你干活。你对雇工的控制是通过编程来实现的。

    • 挂起线程的意思就是你对主动对雇工说:“你睡觉去吧,用着你的时候我主动去叫你,然后接着干活”。
    • 线程睡眠的意思就是你主动对雇工说:“你睡觉去吧,某时某刻过来报到,然后接着干活”。
    • 线程阻塞的意思就是,你突然发现,你的雇工不知道在什么时候没经过你允许,自己睡觉呢,但是你不能怪雇工,肯定你这个雇主没注意,本来你让雇工扫地,结果扫帚被偷了或被邻居家借去了,你又没让雇工继续干别的活,他就只好睡觉了。至于扫帚回来后,雇工会不会知道,会不会继续干活,你不用担心,雇工一旦发现扫帚回来了,他就会自己去干活的。因为雇工受过良好的培训。这个培训机构就是操作系统。

例子:

线程的创建以及等待其终止

#include<iostream>
#include<pthread.h>
#include<unistd.h>

using namespace std;

void *th_fn(void *arg)
{
    cout<<"new thread"<<endl;
    return (void *)10;
}

int main()
{
    pthread_t ptid;
    void *tret;

    pthread_create(&ptid, NULL,th_fn ,NULL);

    pthread_join(ptid, &tret);
    cout<<"code 2 exit id = "<<(int)tret<<endl;
    
    return 0;
}
View Code

运行结果:

 


线程的属性与限制

线程限制

线程的限制可以通过 sysconf 函数来进行查询。

    • PTHREAD_DESTRUCTOR_ITERATIONS    线程退出时,操作系统实现试图销毁线程私有数据的最大次数。
    • PTHREAD_KEYS_MAX                                进程可以创建的键的最大数目
    • PTHREAD_STACK_MIN                               一个线程的栈可用的最小字节数
    • PTHREAD_THREADS_MAX                         进程可以创建的最大线程数

线程的属性

初始化线程属性/销毁线程属性

    • pthread_attr_init(..)
    • pthread_attr_destroy(..)

如果要去除对  pthread_attr_t 结构的初始化,可以调用 pthread_attr_destroy 函数。如果 pthread_attr_init 实现时为属性对象分配了动态内存空间,pthread_attr_destroy 将会释放内存空间。除此之外, pthread_attr_destroy 还会用无效的值初始化属性对象,因此如果该属性对象被误用,将会导致 pthread_create 函数返回错误。

    • detachstate(..)   线程的分离状态属性(如果对现有的某个线程的终止状态不感兴趣的话,可以使用 pthread_detach 函数让操作系统在线程退出时收回它所占用的资源)
    • guardsize(..)    线程栈末尾的警戒缓冲区大小
    • stackaddr(..)    线程栈的最低地址
    • stacksize(..)    线程栈的大小

设置和获得线程的分离属性

    • pthread_attr_getdetachstate(..)
    • pthread_attr_setdetachstate(..)


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM