Linux环境:C编程之多线程
线程的创建与退出
线程创建函数
函数原型:
int pthread_create(pthread_t* thread, pthread_attr_t * attr, void *(*start_routine)(void *), void * arg);
返回值与参数:
- 返回值:成功,则返回 0;失败,则返回对应错误码。
- 参数
thread
是传出参数,保存新线程的标识; - 参数
attr
是一个结构体指针,结构中的元素分别指定新线程的运行属性,attr
可以用pthread_attr_init
等函数设置各成员的值,但通常传入为NULL
即可; - 参数
start_routine
是一个函数指针,指向新线程的入口点函数,线程入口点函数带有一个void *
的参数由pthread_create
的第 4 个参数传入; - 参数
arg
用于传递给第 3 个参数指向的入口点函数的参数,可以为NULL
,表示不传递。
线程退出
void pthread_exit(void *retval);
函数 pthread_exit
用在线程函数中表示线程的退出。其参数可以被其它线程用 pthread_join
函数捕获。
int pthread_join(pthread_t th, void **thread_return);
用于回收线程返回值,相当于进程中的wait
或waitpid
th
指定要回收的线程,thread_return
是一个传出参数,接收线程函数的返回值。
示例程序
创建一个子线程,传入数值1,在子线程中能够获取并打印,子线程退出,返回数值2,主线程通过pthread_join获取等待子线程结束并获取子线程的退出值并打印
#include <fun.h>
void* thread1(void * val)
{
printf("线程创建成功,传入参数:%d\n",(int)val);
pthread_exit((void *)2);
}
int main(int args,char *argv[])
{
pthread_t p=0;
int ret = pthread_create(&p,NULL,thread1,(void *)1);
THREAD_CHECK(ret,"pthread_create")
pthread_join( p,(void **)&ret);
printf("父进程回收:%d\n",ret);
return 0;
}
执行效果:
线程的终止与清理
线程终止
int pthread_cancel(pthread_t thread);
//向thread线程发送cancel信号- 通过其他线程向目标线程发送cancel信号可以使目标线程按照设计好的方式终止。
- 目标线程收到信号后或者忽略、或者立即终止、或者继续运行至
cancelation-point
(取消点)后结束。 - 取消点一般是能引起阻塞的系统调用,在设置取消点时应在系统调用前后加上
pthread_testcancel()
调用来符合到 POSIX 标准。
线程清理
线程运行过程中常常会意外终止,无法正常释放掉自己所占用的资源从而对其他线程造成影响,或者造成系统资源浪费,所以需要引入线程清理机制。
POSIX 线程 API 提供了以下函数对用于在进程结束时自动释放资源:
void pthread_cleanup_push(void (*routine) (void *), void *arg)
/void pthread_cleanup_pop(int execute)
- 用法:在线程中成对出现,对两个函数段之间的代码段进行保护,如果线程运行在清理函数中间的代码段时终止,则执行定义好的清理函数。如果有多个清理函数对,则遵循先入后出的规则,类似括号匹配规则
pthread_cleanup_push
函数的参数为一个函数指针指向清理函数,和传给该清理函数的参数pthread_cleanup_pop
函数从参数为0表示执行到该函数时不执行清理函数,参数非0则执行清理函数。该参数不影响线程在pthread_cleanup_pop
之前退出时的自动清理。
示例程序
创建一个子线程,子线程申请内存,通过清理函数进行free,子线程停留在read标准输入,主线程cancel子线程,子线程能够通过清理函数free对应的malloc的内存
#include <fun.h>
void freept(void * p)
{
printf("开始清理!\n");
free(