
3
它是一个线程的标识符。函数 pthread_create 用来创建一个线程,它的原型为:
extern int pthread_create __P ((pthread_t *__thread, __const pthread_attr_t *__attr,void
*(*__start_routine) (void *), void *__arg));
第一个参数为 指向线程标识符的指针 , 第二个参数用来设置 线程属性 , 第三个参数是 线
程运行函数的起始地址 , 最后一个参数是 运行函数的参数 。 这里 , 我们的函数 thread 不需要
参数 , 所以最后一个参数设为空指针 。 第二个参数我们也设为空指针 , 这样将生成默认属性
的线程。对线程属性的设定和修改我们将在下一节阐述。 当创建线程成功时,函数返回 0
,
若不为 0 则说明创建线程失败,常见的错误返回代码为 EAGAIN 和 EINVAL 。前者表示系
统限制创建新的线程,例如线程数目过多了;后者表示第二个参数代表的线程属性值非法
。
创建线程成功后 , 新创建的线程则运行参数三和参数四确定的函数 , 原来的线程则继续运行
下一行代码。
函数 pthread_join 用来等待一个线程的结束 。函数原型为:
extern int pthread_join __P ((pthread_t __th, void **__thread_return));
第一个参数为被等待的线程标识符 , 第二个参数为一个用户定义的指针 , 它可以用来存
储被等待线程的返回值 。 这个函数是一个线程阻塞的函数 , 调用它的函数将一直等待到被等
待的线程结束为止 , 当函数返回时 , 被等待线程的资源被收回 。 一个线程的结束有两种途径
,
一种是象我们上面的例子一样 , 函数结束了 , 调用它的线程也就结束了 ; 另一种方式是通过
函数 pthread_exit 来实现。 它的函数原型为:
extern void pthread_exit __P ((void *__retval)) __attribute__ ((__noreturn__));
唯一的参数是函数的返回代码,只要 pthread_join 中的第二个参数 thread_return 不 是
NULL , 这个值将被传递给 thread_return 。 最后要说明的是 , 一个线程不能被多个线程等待
,
否则第一个接收到信号的线程成功返回,其余调用 pthread_join 的线程则返回错误代 码
ESRCH 。
在这一节里 , 我们编写了一个最简单的线程 , 并掌握了 最常用的三个函 数 pthread_create
,
pthread_join 和 pthread_exit 。 下面 , 我们来了解线程的一些常用属性以及如何设置这些属性
。
修改线程的属性
在上一节的例子里,我们用 pthread_create 函数创建了一个线程,在这个线程中,我们
使用了默认参数 , 即将该函数的第二个参数设为 NULL 。 的确 , 对大多数程序来说 , 使用默
认属性就够了,但我们还是有必要来了解一下线程的有关属性。
属性结构为 pthread_attr_t , 它同样在头文件 /usr/include/pthread.h 中定义 , 喜欢追根问底
的人可以自己去查看。 属性值不能直接设置,须使用相关函数进行操作,初始化的函数 为
pthread_attr_init , 这个函数必须在 pthread_create 函数之前调用 。 属性对象主要包括是否绑定
、
是否分离 、 堆栈地址 、 堆栈大小 、 优先级 。 默认的属性为非绑定 、 非分离 、 缺省 1M 的堆栈
、
与父进程同样级别的优先级。
关于线程的绑定,牵涉到另外一个概念:轻进程( LWP : Light Weight Process ) 。轻进
程可以理解为内核线程 , 它位于用户层和系统层之间 。 系统对线程资源的分配 、 对线程的控
制是通过轻进程来实现的 , 一个轻进程可以控制一个或多个线程 。 默认状况下 , 启动多少轻
进程 、 哪些轻进程来控制哪些线程是由系统来控制的 , 这种状况即称为非绑定的 。 绑定状况
下 , 则顾名思义 , 即某个线程固定的 " 绑 " 在一个轻进程之上 。 被绑定的线程具有较高的响应
速度,这是因为 CPU 时间片的调度是面向轻进程的,绑定的线程可以保证在需要的时候它
总有一个轻进程可用 。 通过设置被绑定的轻进程的优先级和调度级可以使得绑定的线程满足
诸如实时反应之类的要求。