线程的创建&属性

本文介绍了Linux线程的创建、属性以及终止方式。详细讲解了pthread_create、pthread_exit、pthread_join和pthread_detach等函数的用法,并阐述了线程的分离状态、竞争域、调度继承性、调度策略等属性。

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

注:笔者这些文档多出自APUE这本书,旨在督促自己坚持学习,其中没有给出实际的编码例子,是因为本身快速学习的原则,即“花20%的时间掌握80%的内容”,具体的实战会在后续网络编程中一一体现。个人觉得学习编程最佳的路径是在解决问题中掌握知识点。因此线程这几篇都只会讲述个人理解的基础概念。

线程创建的相关函数:

1.  int pthread_create(pthread_t*thread, const pthread_attr_t *attr, void*(*start_routine) (void *),  void *arg);  

返回值:若成功,返回0;否则返回错误编号

Eg.

pthread_t  thread_id;

pthread_create(thread_id, &attr,&thread_start, &tinfo[tnum]);

  • thread_id---------线程创建成功后用于存放线程ID的位置
  • attr--------------线程的属性,若设置为NULL则表示默认
  • thread_start------新创建的线程从thread_start函数的地址开始运行
  • tinfo[tnum]-------需要向thread_start函数传递的参数
2.  int pthread_equal(pthread_t t1, pthread_t t2);

返回值:对比t1和t2两个线程是否相等,若相等返回非0数值;否则,返回0

  •  线程ID只有在它所属的进程上下文中才有意义,这点和进程ID是有区别的。
3.  pthread_t pthread_self(void);---获取线程自身的线程ID

返回值:调用线程的线程ID

线程终止:

线程的终止分为两大类:主动终止,被动终止

主动终止

  •  线程函数执行return正常返回,返回值就是线程的退出码;
  •  线程调用pthread_exit函数,其参数就是线程的退出码;

被动终止

  • 在其他线程中调用pthread_cancel函数;
  • 任意线程调用exit家族的函数,这种方式比较极端,会导致整个进程退出;

1.  void pthread_exit(void*retval);

Eg.

pthread_exit((void *)2);

  • retval-----------线程的返回值,即终止状态
2.  int pthread_cancel(pthread_t thread);

返回值:若成功,返回0,;否则,返回错误编号

  • 线程通过调用这个函数来请求(并不等待线程终止,它仅仅是提出请求)取消同一进程中的其他线程。

             它的行为等同于pthread_exit(PTHREAD_CANCELED);

3.  int pthread_join(pthread_tthread, void **retval);

返回值:若成功,返回0;否则,返回错误编号

调用线程将一直阻塞,直到指定的线程调用pthread_exit,从启动例程中返回或者被取消。

retval------如果线程从启动例程中返回,则retval就包含返回码

retval------如果线程被取消,就由retval指定的单元被设置为PTHREAD_CANCELED

  • 在调用pthread_join的时候还需要直到线程的启动状态,如果线程是分离状态启动的那么,pthread_join调用就会失败,返回EINVAL,如果是以非分离状态启动的pthread_join就会把线程置于分离状态,这样就可以回收线程资源。
4.    如果线程被设置为分离状态,那么线程的底层存储资源可以在线程终止时立即被回收,那么我们怎么将线程设置为分离状态呢?

int pthread_detach(pthread_tthread);

返回值:若成功,返回0;否则,返回错误编号。


线程清理处理程序:

线程可以安排它退出时需要调用的函数,这与进程在退出时可以使用atexit函数注册退出函数类似。

一个线程可以建立多个清理处理程序。处理程序记录在栈中,也就是说,他们执行顺序与他们注册时相反。

1.   void pthread_cleanup_push(void (*rtn)(void *), void *arg);

rtn------清理函数rtn是由pthread_cleanup_push函数调度的,调用时只有一个参数arg;

2.  voidpthread_cleanup_pop(intexecute);

execute------参数设置为0时,清理函数不被调用。

无论如何pthread_cleanup_pop都将会删除上次pthread_cleanup_push调用建立的清理处理程序。

注意:pthread_cleanup_push和pthread_cleanup_pop必须成对使用。这个可以做个试验测试一下,注释掉你的pthread_cleanup_pop编译会产生什么结果。

线程和进程之间的相似之处:

进程原语

线程原语

描述

fork                            

pthread_create                        

创建新的控制流

exit

pthread_exit

从现有的控制流中退出

waitpid

pthread_join

从控制流中得到退出状态     

atexit

pthread_cleanup_push

注册退出清理函数

getpid

pthread_self

获取控制流ID

abort

pthread_cancel

请求控制流的非正常退出


线程属性:

在前面创建线程的时候我们调用pthread_create函数中有个参数,

const pthread_attr_t *attr是关于设置线程属性的。

接下来就详细总结一下Linux线程的属性。

pthread_attr_t 这个结构体表示将为创建的线程指定类型,该类型的结构体包含了如下属性:

1. detachstate:线程的分离属性          

它表示线程结束的时候,是否回收资源。

  • PTHREAD_CREATE_JOINABLE:这种是默认属性,表示在线程结束时不回收资源,需要调用pthread_join函数来回收;
  • PTHREAD_CREATE_DETACHED:表示线程结束,直接释放资源;

用于设置和获取detach state的函数如下:

int pthread_attr_setdetachstate(pthread_attr_t *attr,int *detachstate);

int pthread_attr_getdetachstate(const pthread_attr_t*restrict attr, int *detachstet );

2.  scope:线程的竞争域

该属性有两种:

  • PTHREAD_SCOPE_SYSTEM:表示线程和整个操作系统中的线程进行竞争;
  • PTHREAD_SCOPE_PROCESS:表示线程只和当前进程内的线程进行竞争,比如线程调度的时候只考虑当前进程中的线程;

用来设置和获取scope的函数如下:

int pthread_attr_setscope(pthread_attr_t *attr, int scope);

int pthread_attr_getscope(const  pthread_attr_t*attr, int *scope);

3.  inheritscheduler:调度继承性

该属性有两种:

  • PTHREAD_INHERIT_SCHED:继承进程的调度策略
  • PHTREAD_EXPLICIT_SCHED:不使用继承的调度策略,而是使用自己提供的调度策略。

用来设置和获取inherit scheduler的函数如下:

int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched);

int pthread_attr_ getinheritsched(const  pthread_attr_t*attr, int *inheritsched);

4.  schedulingpolicy:调度策略

分两大类:

  • 普通调度策略(非实时的调度策略):主要包括SCHED_OTHER、SCHED_BATCH和SCHED_IDLE
  • 实时调度策略:主要包括SCHED_FIFO和SCHED_RR

用于设置和获取policy的函数如下:

int pthread_attr_setschedpoilcy (pthread_attr_t *attr, int poilcy);

int pthread_attr_ getschedpoilcy(const  pthread_attr_t*attr, int *poilcy);

5.  schedulingpriority:线程优先级

使用如下函数来设置和获取:

pthread_attr_setschedparm(pthread_attr_t *attr,const structsched_param *param);

pthread_attr_getschedparm(pthread_attr_t *attr, struct sched_param *param);

6.  guardsize:警界缓冲区大小,默认值是PAGE_SIZE(4096KB)

用来设置和获取线程栈末尾的警戒缓冲区大小,如果线程栈运行到了警戒区,就会收到信号。

使用如下函数来设置和获取:

int pthread_attr_getguardsize(constpthread_attr_t *attr, size_t *guardsize);

int pthread_attr_setguardsize(pthread_attr_t*attr, size_t guardsize);

7.  stackaddress:栈起始地址(栈最低内存地址)

一般来说在X86或者X64处理器上,栈都是往地地址方向的,所以该值一般表示栈的末尾(栈顶)

使用如下两个函数来对其进行设置和获取:

int pthread_attr_getstack(constpthread_attr_t *attr, void **stackaddr,         size_t *stacksize);

int pthread_attr_setstack(pthread_attr_t*attr, void *stackaddr, size_t stacksize);

8.  stacksize:栈大小

对于栈的大小,可以使用如下函数进行设置和获取:

intpthread_attr_getstacksize(constpthread_attr_t *attr, size_t*stacksize);

intpthread_attr_setstacksize(pthread_attr_t*attr,   size_tstacksize);

以上属性目前我最常用的就是detach state(线程的分离属性)。

















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值