一,线程常见函数介绍
-
#include
-
#include
-
void *thread_routine(void *arg)
-
{
-
pthread_t tid=pthread_self();
-
printf("thread 1 say hello\n");
-
return arg;
-
}
-
int main()
-
{
-
pthread_t thread_id;
-
void * thread_result;
-
int status;
-
status=pthread_create(&thread_id,NULL,thread_routine,NULL);
-
if(status!=0)
-
{
-
printf("create error\n");
-
return 1;
-
}
-
status=pthread_join(thread_id,&thread_result);
-
if(status!=0)
-
{
-
printf("join error\n");
-
return 1;
-
}
-
if(thread_result==NULL)
-
return 0;
-
else
-
return 1;
-
}
首先看上面这个例子,简单的创建一个线程,在线程中打印thread 1 say hello。
首先分析上面程序涉及的函数。
1,创建线程,线程通过调用pthread_create函数来创建其他线程,原型如下:
-
#include
-
typedef void*(func)(void*);
-
int pthread_create(pthread_t *tid, const pthread_attr_t *attr,func *f, void *arg); 若成功返回0,若出错则非0
1.1
当pthread_create返回时,参数tid包含新创建线程的ID,新线程可以通过pthread_self函数获取自己线程的ID。
#include
pthread_t pthread_self();
1.2 线程创建属性
pthread_create()中的attr参数是一个结构指针,结构中的元素分别对应着新线程的运行属性,主要包括以下几项:
__detachstate,表示新线程是否与进程中其他线程脱离同步,如果置位则新线程不能用pthread_join()来同步,且在退出时
自行释放所占用的资源。缺省为pthread_CREATE_JOINABLE状态。这个属性也可以在线程创建并运行以后用
pthread_detach()来设置,而一旦设置为pthread_CREATE_DETACH状态(不论是创建时设置还是运行时设置)则不能再恢复
到pthread_CREATE_JOINABLE状态。
__schedpolicy,表示新线程的调度策略,主要包括SCHED_OTHER(正常、非实时)、SCHED_RR(实时、轮转法)和
SCHED_FIFO(实时、先入先出)三种,缺省为SCHED_OTHER,后两种调度策略仅对超级用户有效。运行时可以用过
pthread_setschedparam()来改变。
__schedparam,一个struct
sched_param结构,目前仅有一个sched_priority整型变量表示线程的运行优先级。这个参数仅当调度策略为实时(即SCHED_RR
或SCHED_FIFO)时才有效,并可以在运行时通过pthread_setschedparam()函数来改变,缺省为0。
__inheritsched,有两种值可供选择:pthread_EXPLICIT_SCHED和
pthread_INHERIT_SCHED,前者表示新线程使用显式指定调度策略和调度参数(即attr中的值),而后者表示继承调用者线程的值。缺省
为pthread_EXPLICIT_SCHED。
__scope,表示线程间竞争CPU的范围,也就是说线程优先级的有效范围。POSIX的标准中定义了两个
值:pthread_SCOPE_SYSTEM和pthread_SCOPE_PROCESS,前者表示与系统中所有线程一起竞争CPU时间,后者表示仅
与同进程中的线程竞争CPU。目前LinuxThreads仅实现了pthread_SCOPE_SYSTEM一值。
pthread_attr_t结构中还有一些值,但不使用pthread_create()来设置。
为了设置这些属性,POSIX定义了一系列属性设置函数,包括pthread_attr_init()、pthread_attr_destroy()和与各个属性相关的pthread_attr_get---/pthread_attr_set---函数。
1.3 线程创建的Linux实现
我们知道,Linux的线程实现是在核外进行的,核内提供的是创建进程的接口do_fork()。内核提供了两个系统调用__clone()和
fork(),最终都用不同的参数调用do_fork()核内API。当然,要想实现线程,没有核心对多进程(其实是轻量级进程)共享数据段的支持是不行
的,因此,do_fork()提供了很多参数,包括CLONE_VM(共享内存空间)、CLONE_FS(共享文件系统信息)、
CLONE_FILES(共享文件描述符表)、CLONE_SIGHAND(共享信号句柄表)和CLONE_PID(共享进程ID,仅对核内进程,即0号
进程有效)。当使用fork系统调用时,内核调用do_fork()不使用任何共享属性,进程拥有独立的运行环境,而使用
pthread_create()来创建线程时,则最终设置了所有这些属性来调用__clone(),而这些参数又全部传给核内的do_fork(),从
而创建的"进程"拥有共享的运行环境,只有栈是独立的,由__clone()传入。
Linux线程在核内是以轻量级进程的形式存在的,拥有独立的进程表项,而所有的创建、同步、删除等操作都在核外pthread库中进行。pthread
库使用一个管理线程(__pthread_manager(),每个进程独立且唯一)来管理线程的创建和终止,为线程分配线程ID,发送线程相关的信号
(比如Cancel),而主线程(pthread_create())的调用者则通过管道将请求信息传给管理线程。
2,回收终止线程的资源
缺省为pthread_CREATE_JOINABLE状态,上面的程序采用默认设置,即需要线程通过调用pthread_join函数等待其他线程终止
-
#include
-
int pthread_join(pthread_t tid,void **thread_retrun); 若成功返回0,出错则非零
pthread_join函数会阻塞,直到线程tid终止,然后回收已终止线程占用的所有存储器资源。
除此还要熟悉一下几个函数
-
#include
-
int pthread_detach(pthread_t tid);
-
int pthread_exit(void*thread_return);
-
int pthread_cancel(pthread_t);
pthread_detach()函数
用于指示应用程序在线程tid终止时回收其存储空间。如果tid尚未终止,pthread_detach()不会终止该线程。
一个线程是以一下方式之一来终止的:当顶层的线程例程返回时,线程会隐式的终止;通过调养pthread_exit函数显式的终止,该函数返回一个
指向thread_return的指针。如果主线程调用pthread_exit,它会等待所有其他对等线程终止,然后再终止主线程和整个进程,返回值为
thread_return。对等线程也可以调用pthread_cancel来终止当前线程。
二,线程的生命周期
通常将线程的状态分为以下几种:就绪,运行,阻塞,终止,状态转移图如下所示。
线程的创建,上例中status=pthread_create(&
thread_id,NULL,thread_routine,NULL);完成线程的创建工作,线程创建注意:pthread_create函数返回同
线程执行之间没有同步关系,被创建之后进入就绪状态。线程启动,即开始执行pthread_routine函数。通常线程在以下情况被阻塞:试图加锁一个
已经锁住的互斥量;等待某个条件变量;执行无法立即完成的I/O操作。程序中pthread_join函数处阻塞,等待它创建的线程结束。线程终止,本例
中线程pthread_routine线程资源在pthread_join函数返回时被回收。而pthread_detach分离的线程在线程结束时自动
被回收。
阅读(944) | 评论(0) | 转发(0) |