创建线程

线程创建和进程创建不同,因为在线程之间不存在父子关系。

所有线程(除了创建进程时自动被创建的初始线程)都在相同的层次级别上。 线程并不维护已创建线程的列表,也不知道创建它的线程。

创建线程时,必须指定入口点例程和参数。 每个线程有带有一个参数的入口点例程。 同一个入口点例程可能被多个线程使用。

线程具有属性,用于指定线程的特征。 要控制线程属性,必须在创建线程之前定义线程属性对象。

线程属性对象

线程属性被存储在不透明对象线程属性对象中,在创建线程时使用。 它包含多个属性,这取决于 POSIX 选项的实现。 通过类型为 pthread_attr_t的变量访问该对象。 在AIX 中,pthread_attr_t数据类型是指向结构体的指针;在其他系统中,它可能是结构体或其他数据类型。

创建和破坏线程属性对象

o

线程属性对象由 pthread_attr_init 子例程初始化为缺省值。 这些属性由子例程处理。 线程属性对象被 pthread_attr_destroy 子例程破坏。 此子例程能够释放 pthread_attr_init 子例程动态分配的存储空间,这取决于线程库的实现。

在下面的示例中,创建线程属性对象并将其初始化为缺省值,然后使用该对象,最终删除它:

pthread_attr_t attributes;
                /* the attributes object is created */
...
if (!pthread_attr_init(&attributes)) {
                /* the attributes object is initialized */
        ...
                /* using the attributes object */
        ...
        pthread_attr_destroy(&attributes);
                /* the attributes object is destroyed */
}

同一个属性对象能用来创建多个线程。 在创建两个线程之间也能修改它。 当创建线程后,可以删除属性对象而不影响由它创建的线程。

Detachstate 属性

始终定义以下属性:

Detachstate
指定线程的已拆离状态。

该属性的值由 pthread_attr_get自治区 子例程返回; 它可以由 pthread_attr_set拆卸状态 子例程设置。 此属性的可能值为下面的符号常量:

PTHREAD_CREATE_DETACHED
指定将在已拆离状态创建线程
PTHREAD_CREATE_JOINABLE
指定在可连接状态创建线程

缺省值为 PTHREAD_CREATE_JOINABLE

如果您在可连接状态创建线程,您必须对线程调用 pthread_join 子例程。 否则,创建新线程时,您可能耗尽存储空间,因为每个线程都会占用大量内存。 有关 pthread_join 子例程的更多信息,请参阅 调用 pthread_join 子例程。

其他线程属性

AIX 还定义了以下属性,这些属性适用于高级程序,并且可能需要特殊执行特权才能生效。 使用缺省设置,大多数程序能够正确运行。 使用继承的属性 中说明了如何使用以下属性。

争用作用域
指定线程的争用作用域
Inheritsched
指定线程的调度属性的继承
Schedparam
指定线程的调度参数
Schedpolicy
指定线程的调度策略

堆栈属性中说明了如何使用以下堆栈属性。

Stacksize
指定线程的堆栈大小
Stackaddr
指定线程的堆栈地址
Guardsize
指定线程的堆栈保护区大小

使用 pthread_create 子例程创建线程

通过调用 pthread_create 子例程来创建线程。 此子例程创建新线程并使其能够运行。

使用线程属性对象

调用 pthread_create 子例程时,您可以指定线程属性对象。 如果您指定了 NULL 指针,被创建的线程将具有缺省属性。 因而,以下代码片段:

pthread_t thread;
pthread_attr_t attr;
...
pthread_attr_init(&attr);
pthread_create(&thread, &attr, init_routine, NULL);
pthread_attr_destroy(&attr);
等同于以下代码:
pthread_t thread;
...
pthread_create(&thread, NULL, init_routine, NULL);

入口点例程

在调用 pthread_create 子例程时,您必须指定入口点例程。 您的程序提供的例程与进程的 main 例程相似。 它是新线程执行的第一个用户例程。 当线程从其例程返回时,线程被自动终止。

入口点例程有一个参数(空指针),它是在调用 pthread_create 子例程时指定的。 您可以指定指向某些数据(例如:字符串或者结构)的指针。 创建线程(调用 pthread_create 子例程的线程)和被创建线程必须在此指针的实际类型上保持一致。

入口点例程返回空指针。 在线程终止之后,线程库将存储此指针,除非线程已拆离。 有关使用此指针的更多信息,请参阅 从线程返回信息

返回的信息

pthread_create 子例程返回新线程的线程标识。 调用程序能够使用此线程标识在线程上执行各种操作。

根据两个线程的调度参数,新线程可能在对 pthread_create 子例程的调用返回之前就开始运行。 甚至可能当 pthread_create 子例程返回时,新线程已经被终止。 这时 pthread_create 子例程通过 thread 参数返回的线程标识已经无效。 因此检查使用线程标识作为参数的线程库子例程返回的 ESRCH 错误代码很重要。

如果 pthread_create 子例程不成功,那么不创建新线程, thread 参数中的线程标识为无效且返回适当的错误代码。 有关更多信息,请参阅 多线程程序示例

处理线程标识

新创建的线程的线程标识通过 thread 参数被返回给创建线程。 当前线程标识由 pthread_self 子例程返回。

线程标识是不透明对象; 其类型为 pthread_t。 在 AIX中, pthread_t 数据类型是整数。 在其他系统上,可能是结构、指针或者其他数据类型。

要改善使用线程库的程序的可移植性,应该始终将线程标识作为非透明对象处理。 因此,应该使用 pthread_equal 子例程来比较线程标识。 请不要使用 C 等于运算符 (==),因为 pthread_t 数据类型不可为算术类型或者指针。